題目: 將兩個升序鏈表合併為一個新的升序鏈表並返回。新鏈表由原節點拼接而成 (不創建新節點)。
示例: l1: 1→2→4, l2: 1→3→4 → 1→1→2→3→4→4
dummy 虛擬頭節點,tail 指針追蹤合併鏈表尾部。l1 和 l2,比較節點值,將較小節點接在 tail 後,推進對應指針與 tail。tail 後 (已有序,無需逐個比較)。dummy.next。class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
tail.next = l1;
l1 = l1.next;
} else {
tail.next = l2;
l2 = l2.next;
}
tail = tail.next; // 尾指針前移
}
// 連接剩餘部分 (二者必有一為 null)
tail.next = (l1 != null) ? l1 : l2;
return dummy.next;
}
}
初始: dummy → null
tail
l1: 1 → 3 → 5
l2: 2 → 4 → 6
比較 1 vs 2 → 接 1
dummy → 1
tail
l1: 3 → 5
l2: 2 → 4 → 6
比較 3 vs 2 → 接 2
dummy → 1 → 2
tail
l1: 3 → 5
l2: 4 → 6
... 以此類推
dummy, tail),符合原地合併要求。l1.val 和 l2.val,值較小的節點作為**當前合併結果的頭節點**。next 指向 剩餘部分的合併結果 (即遞歸調用)。class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
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;
}
}
}
tail 始終指向當前尾節點。tail.next = ... **之後** 執行 tail = tail.next,否則丟失鏈接。tail.next = l1 != null ? l1 : l2 一步到位,避免多餘循環。<= 而非 <,保證相等值時 l1 節點在前,維持相對順序 (穩定合併)。next 指針,原節點對象不變,滿足題目「拼接原節點」要求。| 維度 | 迭代 (虛擬頭節點) | 遞歸 |
|---|---|---|
| 空間複雜度 | O(1) ✅ | O(m+n) ❌ |
| 代碼行數 | ~12 行 | ~8 行 |
| 可讀性 | 中 (指針操作) | 高 (聲明式) |
| 棧溢出風險 | 無 | 長鏈表有風險 |
| 推薦場景 | 生產代碼、長鏈表、嚴格空間限制 | 面試快速寫出、短鏈表、教學演示 |
本題是合併 K 表的基礎子問題。K 表合併優化方案:
掌握「虛擬頭節點 + 雙指針」迭代模板,不僅能高效解決合併兩有序鏈表,更是「合併 K 表」「歸併排序鏈表」「刪除鏈表倒數第 N 個節點」等經典題目的核心構建塊。