1. 程式人生 > 實用技巧 >合併兩個有序連結串列

合併兩個有序連結串列

1.問題描述

將兩個升序連結串列合併為一個新的 升序 連結串列並返回。新連結串列是通過拼接給定的兩個連結串列的所有節點組成的。

示例:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

2.求解

迭代

  1. 設定啞節點dummy,便於我們返回連結串列
  2. 當l1和l2非空時,遍歷l1、l2連結串列,比較他們的值,將dummy的next指向值較小的節點,並將較小值節點指向下一個節點
  3. 當遍歷完成時,判斷l1、l2是否仍然非空,將dummy指向非空節點
程式碼如下
/*
執行用時:0 ms, 在所有 Java 提交中擊敗了100.00% 的使用者
記憶體消耗:38.3 MB, 在所有 Java 提交中擊敗了89.31% 的使用者
*/
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode l3 = new ListNode(0);
    ListNode dummy = l3;
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            l3.next = l1;
            l1 = l1.next;
        } else {
            l3.next = l2;
            l2 = l2.next;
        }
        l3 = l3.next;
    }
    if (l1 != null) {
        l3.next = l1;
    } else {
        l3.next = l2;
    }
    return dummy.next;
}
  • 時間複雜度O(m + n),m、n分別是兩個連結串列長度,至多每個節點都會呼叫一次
  • 空間複雜度O(1),只使用了常數級的空間

遞迴

  • 遞:每次深入是值較小的節點
  • 歸:當遇到一個節點為null時,開始返回
程式碼如下
/*
執行用時:0 ms, 在所有 Java 提交中擊敗了100.00% 的使用者
記憶體消耗:38.4 MB, 在所有 Java 提交中擊敗了76.99% 的使用者
*/
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    return access(l1, l2);
}

public ListNode access(ListNode l1, ListNode l2) {
    if (l1 == null) {
        return l2;
    }
    if (l2 == null) {
        return l1;
    }
    if (l1.val < l2.val) {
        l1.next = access(l1.next, l2);
        return l1;
    } else {
        l2.next = access(l1, l2.next);
        return l2;
    }
}
  • 時間複雜度O(m + n),m、n分別是兩個連結串列長度,至多每個節點都會呼叫一次
  • 空間複雜度O(m + n),每次呼叫方法都會消耗棧空間,棧空間的大小取決於遞迴的深度,最多遞迴m + n次

ps:遞迴的空間複雜度不一定都是呼叫方法的次數,若函式在尾位置呼叫自身(或是一個尾呼叫本身的其他函式等等),則稱這種情況就是尾遞迴。java語言對尾遞迴進行了優化,尾遞迴佔用的棧空間是常數級的(能優化成尾遞迴說明可以寫成迭代)

尾遞迴的優化