写这个主要是为了记录自己学习的情况,题有哪些好的解法,用到什么样的知识点,整理一下思绪。
 

  • 题目
  • 题解
  • 迭代法
  • 递归法
  • 总结

题目

java 两个list 按顺序 合并成一个list_递归


题目链接

这题是简单难度的,两个链表已经是有序状态,思路比较简单。

题解

迭代法

1.设置一个哨兵结点(假结点)pHead,用于作为返回最终结果链表的头指针;
2.设置一个游标p,随着链表结点的增加移动,初始情况下,p指向pHead;
3.在l1、l2均未达到链表结尾(null)前提下循环迭代。
l1当前指向结点的值小于等于l2当前指向结点的值时,p.next指向l1,l1移向下个结点,否则,p.next指向l2,l2移向下个结点;游标p移向下个结点。
4.由于当循环结束时,l1、l2中有一个仍然非空,所以直接将剩余结点添加。

java 两个list 按顺序 合并成一个list_结点_02


初始状态;

java 两个list 按顺序 合并成一个list_结点_03


第一次循环;

java 两个list 按顺序 合并成一个list_递归_04


第二次循环;(以此类推)

java 两个list 按顺序 合并成一个list_链表_05


最后一次循环,l1先达到结尾(null);

java 两个list 按顺序 合并成一个list_递归_06


最后将剩余结点全部添加至p.next;

Java源码:

class Solution2 {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode pHead = new ListNode(-1);//哨兵结点
        ListNode p = pHead;//游标
        while(l1 != null && l2 != null){
            if (l1.val <= l2.val){
                p.next = l1;
                l1 = l1.next;
                p = p.next;
            }else{
                p.next = l2;
                l2 = l2.next;
                p = p.next;
            }
        }
        p.next = l1 == null ? l2 : l1;//添加剩余结点
        return pHead.next;//返回时跳过头结点
    }
}

算法复杂度:

时间复杂度:O(N+M),N和M分别为两个有序链表的长度,循环次数不会超过两个长度之和,其他操作的时间复杂度都是常数级别的;
空间复杂度:O(1),只需要常数的空间存放若干个变量。

递归法

这个我没有想到,看了题解后才知道这个解法!

官方题解中有这样的思路:

java 两个list 按顺序 合并成一个list_递归_07

1.首先,递归终止的条件是l1或l2为空(null);
2.如果l1.val < l2.val的话,表头就是l1的头结点,否则是l2的头结点;
3.递归的内容是得到的两个链表中小的结点后,在剩下的结点中找下一个小的结点;

java 两个list 按顺序 合并成一个list_结点_08


java 两个list 按顺序 合并成一个list_链表_09


java 两个list 按顺序 合并成一个list_结点_10


java 两个list 按顺序 合并成一个list_链表_11


java 两个list 按顺序 合并成一个list_结点_12


java 两个list 按顺序 合并成一个list_递归_13

Java源码:

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null){
            return l2;
        }
        else if (l2 == null){
            return l1;
        }
        else if (l1.val < l2.val){
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else{
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

算法复杂度:

时间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。因为每次调用递归都会去掉 l1 或者 l2 的头节点(直到至少有一个链表为空),函数 mergeTwoList 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O(n+m)。
空间复杂度:O(n+m),递归就是程序内部维护了一个栈,每次将最小值压栈,也就是用一个栈来维护顺序。

总结

两种方法虽然时间复杂度一样,但在我实际试验中,递归法效率比迭代法高。