【LeetCode刷题记录】21.合并两个有序链表——Java实现

写这个主要是为了记录自己学习的情况,题有哪些好的解法,用到什么样的知识点,整理一下思绪。
原文链接https://www.cnblogs.com/HelloXHD/p/12815142.html

题目

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

题解

迭代法

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

初始
初始状态;
第一次循环
第一次循环;
第二次循环
第二次循环;(以此类推)
最后一次循环
最后一次循环,l1先达到结尾(null);
结果
最后将剩余结点全部添加至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),只需要常数的空间存放若干个变量。

递归法

这个我没有想到,看了题解后才知道这个解法!
官方题解中有这样的思路:
递归法思路

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





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),递归就是程序内部维护了一个栈,每次将最小值压栈,也就是用一个栈来维护顺序。

总结

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

posted @ 2020-05-01 22:25  白糖黄连混合物  阅读(296)  评论(0编辑  收藏  举报