判斷單鏈表是否為回文結構。進階要求 O(n) 時間、O(1) 空間。本文提供**快慢指針找中點 + 原地反轉後半部 + 雙指針比較 + 可選恢復鏈表**的完美解法,詳細講解奇偶長度處理、反轉邏輯與邊界條件。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool isPalindrome(struct ListNode* head) {
if (!head || !head->next) return true; // 空或單節點
// 1. 快慢指針找中點
struct ListNode *slow = head, *fast = head;
while (fast->next && fast->next->next) { // 讓 slow 停在中間偏左(偶數)或正中(奇數)
slow = slow->next;
fast = fast->next->next;
}
// 2. 反轉後半部:從 slow->next 開始
struct ListNode *prev = NULL, *curr = slow->next;
slow->next = NULL; // 斷開前半部,便於比較與恢復
while (curr) {
struct ListNode *next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
struct ListNode *head2 = prev; // 反轉後的頭
// 3. 比較前半部與反轉後的後半部
struct ListNode *p = head, *q = head2;
bool result = true;
while (q) { // 只需遍歷後半部(較短或等長)
if (p->val != q->val) {
result = false;
break;
}
p = p->next;
q = q->next;
}
// 4. 可選:恢復鏈表(面試加分,LeetCode 不要求)
// 再次反轉 head2 接回 slow->next
curr = head2; prev = NULL;
while (curr) {
struct ListNode *next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
slow->next = prev;
return result;
}
while (fast->next && fast->next->next)
prev = NULL; curr = start;
while (curr) {
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
new_head = prev;
| 輸入 | 輸出 | 說明 |
|---|---|---|
| 1→2→2→1 | true | 偶數長度回文 |
| 1→2→3→2→1 | true | 奇數長度回文 |
| 1→2 | false | 非回文 |
| 1 | true | 單節點 |
| NULL | true | 空鏈表 |
| 1→1→2→1 | false | 非回文 |
回文鏈表判斷是**快慢指針 + 原地反轉**組合拳的經典考點。關鍵在於:快慢指針停止條件控制 `slow` 位置、反轉起點從 `slow->next` 開始、斷開前半部簡化比較邏輯、可選恢復體現工程素養。熟練掌握此模板,可秒殺「鏈表重排序 (LeetCode 143)」、「判斷鏈表是否為迴文」等變體題。