1. 程式人生 > >LeetCode 234——回文鏈表

LeetCode 234——回文鏈表

val www fast struct 精彩 反轉鏈表 每一個 復雜度 lis

1. 題目

請判斷一個鏈表是否為回文鏈表。

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

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

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

2. 思路

  • 此題可以看做是反轉鏈表 和 鏈表中間結點 的結合。

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

  • 偶數結點情況如下
    技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

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

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

  • 再來看奇數結點的情況

技術分享圖片

技術分享圖片

  • 奇數個結點時,我們依然可以分別得到以 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」!
技術分享圖片

LeetCode 234——回文鏈表