令人头秃的LeetCode——21.合并两个有序链表

题目链接:21. 合并两个有序链表


解法一 迭代

利用迭代法求解,大概是正常人看到此题的第一想法。求解思路与“合并两个有序数组”如出一辙,不同的是,链表不需要开辟新空间用于存放元素。

实现步骤如下:

  • 建立一个新的头节点newHead,用于最后返回有序的链表。同时,初始化节点cur.next = newHead,用于向newHead指向的链表中存放元素。
  • 比较l1.vall2.val的大小。若l1.val <= l2.valcur.next = l1切记!之后需要维护l1cur,再进行下一次循环。l2.val < l1.val,操作同理。
  • 循环在l1l2其一指向null时停止,此时要做的就是将另一个非空的链表接在cur后面。
  • 最后,返回newHead.next
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode newHead = new ListNode();
        ListNode cur = newHead;
        while (l1 != null && l2 != null){
            if (l1.val <= l2.val){
                cur.next = l1;
                l1 = l1.next;
            }else {
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        }
        cur.next = l1 == null ? l2 : l1;
        return newHead.next;
    }

复杂度分析

  • 时间复杂度:O(n+m),两个链表长度分别为n和m。
  • 空间复杂度:O(1),没开新空间。

解法二 递归

递归,本质上是将原来的问题,转化为更小规模的同一问题。

递归函数一般都由两部分组成:求解最基本的问题、把原问题转化成更小的问题。

求解最基本的问题,也就是递归的终止条件。

把原问题转化成更小的问题(递归的等价关系),反过来说,就是用更小规模问题的解去构建原规模的问题。**其中,需要特别注意递归函数的”宏观“语意。**递归函数的目的在于完成一个功能,在求解过程中,我们需要对递归的目的有一个具体明确的认识。

对于此问题,递归函数构建的思路如下:

  • 终止条件:两个链表中其一为空
  • 等价关系:递归函数的目的很明确,返回一个合并好的有序链表,但它不仅仅是合并好的有序链表,且这个有序链表的最小值(头节点)是不小于原规模问题中l1.vall2.val,因此,递归函数的入参应该是l1.vall2.val直接小的值的下一个节点,和大的值所在的节点。例如,若l1.val <= l2.val,则入参为(l1.next, l2)注意!不能是(l1.next, l2.next),因为这样可能会存在l2.val > l1.next.val的情况,这与返回值”不小于“的条件相悖
  • 之后,得到了返回的有序链表,只需与较小值所在的节点合并即可。
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null)
            return l2;
        else if (l2 == null)
            return l1;
        
        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),额,不是很懂。。。官方说取决于合并后链表的长度
  • 空间复杂度:O(n+m),递归深度最大为n+m。

小结

链表,真乃练习递归的神器!

以及,《理解》还是不到位,又是菜菜的一天~

菜到安详表情包

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页