剑指offer系列之十五:合并两个排序的链表

题目描述

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

这道题我的第一思路这样的:可以先遍历这两个排序的链表,把遍历的结果存放在一个集合中,然后调用库函数Arrays.sort方法完成排序,之后,根据这些排好序的结果重新创建一个链表,即为合并之后但仍然排序的链表。但是这种思路需要额外的List和创建链表的空间开销,而且时间复杂度最快也是O(nlogn)。所以不是很理想。第二种思路是这样的:因为两个链表都是排序的,所以可以先比较两个链表的头结点,这样就确定了合并之后链表的第一个节点,之后再比较两个链表的第二个节点(原来较大值与较小值所属链表的第二个节点进行比较),这样依次就能确定合并链表的第二个、第三个节点,故明显是一个递归的过程。参照这个过程实现代码如下(已被牛客AC):

package com.rhwayfun.offer;

public class MergeLinkedList {

    public class ListNode {
        int val;
        ListNode next = null;

        ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode Merge(ListNode list1, ListNode list2) {
        if(list1 == null) return list2;
        if(list2 == null) return list1;

        ListNode mergeListHead = null;
        if(list1.val < list2.val){
            mergeListHead = list1;
            mergeListHead.next = Merge(list1.next, list2);
        }else{
            mergeListHead = list2;
            mergeListHead.next = Merge(list1, list2.next);
        }

        return mergeListHead;
    }

}

上面的递归代码看起来很简洁,但是非递归代码也是需要掌握的,代码如下:

public ListNode Merge2(ListNode list1, ListNode list2) {
        if(list1 == null) return list2;
        if(list2 == null) return list1;

        ListNode mergeList = null;
        ListNode curNode = null;

        //初始化第一个节点
        if(list1.val < list2.val){
            curNode = list1;
            list1 = list1.next;
            curNode.next = null;
            mergeList = curNode;
        }else{
            curNode = list2;
            list2 = list2.next;
            curNode.next = null;
            mergeList = curNode;
        }

        while(list1 != null && list2 != null){
            if(list1.val < list2.val){
                curNode = list1;
                list1 = list1.next;
                curNode.next = null;
                mergeList.next = curNode;
                mergeList = mergeList.next;
            }else{
                curNode = list2;
                list2 = list2.next;
                curNode.next = null;
                mergeList.next = curNode;
                mergeList = mergeList.next;
            }
        }

        //处理剩余的结点
        while(list1 != null){
            curNode = list1;
            list1 = list1.next;
            curNode.next = null;
            mergeList.next = curNode;
            mergeList = mergeList.next;
        }
        while(list2 != null){
            curNode = list2;
            list2 = list2.next;
            curNode.next = null;
            mergeList.next = curNode;
            mergeList = mergeList.next;
        }

        return mergeList;
    }
时间: 2024-08-31 14:45:40

剑指offer系列之十五:合并两个排序的链表的相关文章

剑指offer系列之三十五:两个链表的第一个公共节点

题目描述 输入两个链表,找出它们的第一个公共结点. 由于是单链表,所以可以发现从第一个公共节点开始,后面的结点都是相同的,一种思路是从两个链表的尾部开始遍历,直到发现最后一个相同的结点为止,那么这最后一个相同的结点是单链表的角度看就是两个链表的第一个公共节点了.还有一种思路是不需要从尾部开始遍历,毕竟从尾部遍历单链表的话还得使用反转链表的方法进行操作,首先计算出两个链表的长度,让更长的那个单链表先移动两个链表长度差值个位置,然后两个链表同时移动,从更短的那个链表的第一个位置开始遍历,两个链表都往

剑指offer系列之五十五:把二叉树打印成多行

题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 此题实际上与上面一题是重复了,总体还是层序遍历的思路,只不过现在不需要在打印每一行之前对打印顺序进行判断了,所以可以在前面一题的代码进行简单的修改就可以实现题目的要求了.不多说,直接看代码(已被牛客AC): package com.rhwayfun.offer; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue;

剑指offer系列之六十五:机器人的运动范围

题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18.但是,它不能进入方格(35,38),因为3+5+3+8 = 19.请问该机器人能够达到多少个格子? 这题实际与上一题"矩阵中的路径"思路是相似的,都是需要创建一个状态数组对访问的格子进行标记,但是这里需要计算所有能够走的格子总数,实际

剑指offer系列之四十五:左旋转字符串

题目描述 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S="abcXYZdef",要求输出循环左移3位后的结果,即"XYZdefabc".是不是很简单?OK,搞定它! 同上一题思路差不多,可以把需要左旋的字符串看成一部分,其他的字符串看成另一部分,比如字符串"abcdef",需要输出左移2位的结果,可以把字符串&q

剑指offer系列之三十六:数字在排序数组中出现的次数

题目描述 统计一个数字在排序数组中出现的次数. 因为是排序数组,自然联想到二分查找算法,这样我们在二分的时候可能会获取多个相同的数字.就是说,中间那个位置的值可能刚好是统计的那个值,假设为k.那么k还有可能在前面或者后面出现,在这个基础上继续二分当然也是可以的,如果能够在使用二分查找算法的时候统计出第一个k和最后一个k出现的位置,那么k出现的次数自然就确定了.第一个k出现的位置,可以使用二分查找算法,如果中间位置的值刚好是k,那么继续比较中间位置前面位置的值是不是也是k,如果不是那么该中间位置就

剑指offer系列之十二:调整数组顺序使奇数位于偶数前面

题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 这道题第一思路自然是这样的:从头开始遍历这个数组,如果遇到偶数就把这个数之后的所有数往前移动一位,这样数组会留出一个空位,移动完毕之后把该偶数放到该空位即可.这样处理的话需要两次循环,一次是遍历,另一次是移位,所以时间复杂度是O(n2).下面是这种思路的实现代码(已被牛客AC): public void reOrd

剑指offer系列之十九:包含min函数的栈

题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数.要求时间复杂度是O(1). 还是先说一下思路吧,因为每次方元素进栈的时候不能保证栈顶元素都是最小的,所以需要想办法使得栈顶元素始终是最小的元素,排序是一种思路,但是每次排序还设计重新出栈和入栈,想来应该不是这样的.一种思路是可以利用一个辅助栈,相当于是以空间换时间了.具体思路是:当入栈的新元素原先栈顶元素小的话就该元素放入一个辅助栈中,如果新入栈的元素比原先栈顶元素大,则在辅助栈中继续放原先最小的元素.这样一直放下去

剑指offer系列之十八:顺时针打印矩阵

题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. 由于每打印完一圈都会改变其起始坐标,所以需要先确定矩阵大小与这个起始坐标的关系,比如一个4阶矩阵,第一圈的起始坐标是(0,0),第二圈的起始坐标是(1,1),打印两圈之后就打印结束了.在比如一个5阶矩阵,前两圈是一样的,第三圈的

剑指offer系列之三十八:判断是否是平衡二叉树

题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 所谓平衡二叉树就对某个结点来讲,其左子树的深度与右子树深度的绝对值不超过1.由于需要对每个节点进行判断,所以可以采用递归的思路进行解决.具体思路是:先求出根节点的左右子树的深度,并对两者进行判断,如果没有满足左右子树的深度的绝对值不超过1的条件,那么就不是平衡二叉树.下一步,自然就是分别对根节点的左右子树进行递归判断了,这样一直到叶子结点.整棵二叉树的所有节点都判断完毕,所以这个问题就解决了.下面是这种思路的实现代码(已被牛客AC): p