1. 程式人生 > >LeetCode 234——迴文連結串列

LeetCode 234——迴文連結串列

1. 題目

請判斷一個連結串列是否為迴文連結串列。

示例 1: 輸入: 1->2 輸出: false 示例 2:

輸入: 1->2->2->1 輸出: true

進階: 你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?

2. 思路

定義快慢兩個指標,尋找中間結點,同時在慢指標移動的過程中反轉前半部分子連結串列。當找到中間結點時,再分別向前向後比較前後兩個子連結串列的每一個結點值是否相同。

  • 偶數結點情況如下 3.png

4.png

5.png

6.png

  • 此時,我們分別得到了以 slow 為頭指標的前半部分子連結串列和以 p2 為頭指標的後半部分子連結串列。由於中間結點偏向後邊,所以我們需要先比較最中間的兩個結點(此處為 2 和 3 結點)

    ,然後再依次向兩邊迴圈比較直到到達子鏈的鏈尾。

  • 再來看奇數結點的情況

7.png

8.png

  • 奇數個結點時,我們依然可以分別得到以 slow 為頭指標的前半部分子連結串列和以 p2 為頭指標的後半部分子連結串列。此時,由於 slow 指向的中間結點無須比較,我們只需從 slow 後面第一個結點和 p2 指向的結點開始迴圈向兩邊比較即可(此處為 2 和 4 結點)
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution { public: bool isPalindrome(ListNode* head) { if (head == NULL || head->next == NULL) // 空鏈或只有一個結點,返回 true { return true; } else { /* 此為反轉連結串列的三個指標,slow 即代表 p1 */ ListNode*
slow = head; // 慢指標指向第一個結點 ListNode * p2 = slow->next; // 第二個結點 ListNode * p3 = p2->next; // 第三個結點 ListNode* fast = head; // 快指標指向頭結點 // 奇數結點快指標指向最後一個結點結束 // 偶數結點快指標指向 NULL 結束 while(fast && fast->next) { p3 = p2->next; fast = fast->next->next; // 快指標前進兩步 p2->next = slow; // 反轉連結串列 slow = p2; // 慢指標前進一步 p2 = p3; } head->next = NULL; // 處理前半部分子鏈的尾節點 // 偶數結點 if(!fast) { // 先比較 slow 後的兩個結點是否相同 if (slow->val == slow->next->val) { // 以 slow 後的第三個結點和 p2 指向的結點開始迴圈向兩邊比較 slow = slow->next->next; while(slow) { if (slow->val != p2->val) { return false; } else { slow = slow->next; p2 = p2->next; } } return true; } else { return false; } } // 奇數結點 else { // 以 slow 後的第一個結點和 p2 指向的結點開始迴圈向兩邊比較 slow = slow->next; while(slow) { if (slow->val != p2->val) { return false; } else { slow = slow->next; p2 = p2->next; } } return true; } } } };

獲取更多精彩,請關注「seniusen」! seniusen