題目: 給定一個鏈表,兩兩交換相鄰節點,並返回交換後的頭節點。不能修改節點值,只能交換節點本身。空間複雜度 O(1)。
示例: 1→2→3→4 → 2→1→4→3
head == null || head.next == null),直接返回。head 和 head.next 為待交換的第一對 (first, second)。swapPairs(head.next.next) 處理剩餘鏈表,返回新的子鏈表頭 restHead。first.next = restHead (第一個節點指向後續已交換好的鏈表)second.next = first (第二個節點指向第一個,完成交換)second (即原 head.next)。class Solution {
public ListNode swapPairs(ListNode head) {
// 終止條件
if (head == null || head.next == null) {
return head;
}
// 當前待交換的兩個節點
ListNode first = head;
ListNode second = head.next;
// 遞歸處理剩餘節點
ListNode restHead = swapPairs(second.next);
// 交換當前對
first.next = restHead;
second.next = first;
// 返回新頭節點
return second;
}
}
引入 dummy 虛擬頭節點簡化邊界處理 (頭節點可能改變)。維護三個指針:
prev:指向**已處理部分的尾節點** (初始指向 dummy)。first:待交換的第一個節點 (prev.next)。second:待交換的第二個節點 (first.next)。prev → first → second → nextPair
↓ ↓
(斷開) (斷開)
重鏈:
prev.next = second
second.next = first
first.next = nextPair
指針前移:
prev = first
first = nextPair
second = first?.next
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;
while (prev.next != null && prev.next.next != null) {
ListNode first = prev.next;
ListNode second = first.next;
ListNode nextPair = second.next; // 保存下一組頭
// 交換
prev.next = second;
second.next = first;
first.next = nextPair;
// 前移準備下一輪
prev = first;
}
return dummy.next;
}
}
second.next 修改後原鏈接丟失,必須先存 ListNode nextPair = second.next;。first 成為該對的尾節點,下一輪的 prev 應指向它。prev.next != null && prev.next.next != null 確保至少有兩個節點可交換。val 字段。| 維度 | 遞歸 | 迭代 (虛擬頭節點) |
|---|---|---|
| 代碼長度 | 極短 (~10 行) | 中等 (~15 行) |
| 空間複雜度 | O(n) 調用棧 | O(1) 滿足題目硬性要求 |
| 可讀性 | 高 (聲明式) | 中 (指針操作需心理模擬) |
| 棧溢出風險 | 極長鏈表可能棧溢出 | 無風險 |
| 推薦場景 | 面試快速寫出、鏈表較短 | 生產代碼、長鏈表、嚴格 O(1) 空間 |
掌握「虛擬頭節點 + 三指針」迭代模板,不僅能解決此題,更是處理「鏈表局部反轉」「K 個一組翻轉 (LeetCode 25)」「刪除倒數第 N 個節點」等經典鏈表題的通用利器。