給定單向鏈表頭節點 head 與整數 n,找出倒數第 n 個節點 (即正數第 size - n + 1 個)。要求單次遍歷、O(1) 空間。
核心思想: 讓快指針 q 先走 n 步,再與慢指針 p 同步前進。當 q 抵達尾部,p 恰好位於倒數第 n 節點。
struct Node { int val; Node* next; };
Node* findNthToLast(Node* head, int n) {
if (!head || n < 1) return nullptr;
Node *p = head, *q = head;
// q 先走 n 步
for (int i = 0; i < n; ++i) {
if (!q) return nullptr; // 鏈表長度 < n
q = q->next;
}
// 同步前進
while (q) {
p = p->next;
q = q->next;
}
return p;
}
class ListNode { int val; ListNode next; }
public ListNode nthToLast(ListNode head, int n) {
if (head == null || n < 1) return null;
ListNode p1 = head, p2 = head;
// p2 先走 n-1 步 (或 n 步,視邊界定義)
for (int i = 0; i < n - 1; ++i) {
if (p2 == null) return null;
p2 = p2.next;
}
// 同步直到 p2 到達最後一個節點
while (p2.next != null) {
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
思想: 先遍歷一次得長度 len,倒數第 n 即正數第 len - n + 1 個,再走一次。
// 概略碼
int len = 0;
for (Node* cur = head; cur; cur = cur->next) len++;
if (n > len) return null;
int target = len - n + 1;
Node* cur = head;
for (int i = 1; i < target; ++i) cur = cur->next;
return cur;
| 輸入 | 預期回傳 | 處理邏輯 |
|---|---|---|
| head = null | null | 首行判斷 |
| n <= 0 | null | 首行判斷 |
| n > 鏈表長度 | null | 快指針走步時提前遇到 null |
| n == 鏈表長度 | 頭節點 | 快指針走完即為 null,慢指針未動 |
| n == 1 | 尾節點 | 快指針先走 1 步,同步至尾 |
dummy 頭節點簡化邊界。**雙指針法** 是解決「倒數第 K 個」問題的標準解法,單次遍歷、無額外空間、代碼簡潔。面試與實務中請熟練掌握其邊界處理 (n 過大、空鏈表、刪除節點需前驅等)。