Easy草稿★★★★O(n) 時間 · O(1) 空間
Linked ListTwo PointersStack
Patterns🐢 快慢指針↔️ 雙指針🥞 堆疊⛓️ 鏈結串列操作
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

234Palindrome Linked ListLinked ListEasyLinked List

給定一個單向鏈結串列的頭節點 head,判斷該鏈結串列是否為回文(palindrome)。

Example:

Input: head = [1,2,2,1] Output: true

Intuition

TIP

核心思路:找到中點後反轉後半段,再逐一比對前半段與反轉後的後半段。

Approaches

1. Stack — O(n) / O(n)
  • Idea: 將所有節點值壓入 Stack,再從頭遍歷同時從 Stack 彈出比對
  • Time: O(n)
  • Space: O(n) - Stack 儲存所有節點值
class Solution {
    fun isPalindrome(head: ListNode?): Boolean {
        val stack = ArrayDeque<Int>()
        var curr = head
        while (curr != null) {
            stack.addLast(curr.`val`)
            curr = curr.next
        }
        curr = head
        while (curr != null) {
            if (curr.`val` != stack.removeLast()) return false
            curr = curr.next
        }
        return true
    }
}
⭐ 2. Fast-Slow Pointer + Reverse — O(n) / O(1)
  • Idea: 快慢指針找中點,反轉後半段鏈結串列,再逐一比對
  • Time: O(n)
  • Space: O(1) - 只用指針變數
class Solution {
    fun isPalindrome(head: ListNode?): Boolean {
        // 快慢指針找中點
        var slow = head
        var fast = head
        while (fast?.next != null) {
            slow = slow?.next
            fast = fast.next?.next
        }

        // 反轉後半段
        var prev: ListNode? = null
        var curr = slow
        while (curr != null) {
            val next = curr.next
            curr.next = prev
            prev = curr
            curr = next
        }

        // 比對前半段與反轉後的後半段
        var left = head
        var right = prev
        while (right != null) {
            if (left?.`val` != right.`val`) return false
            left = left.next
            right = right.next
        }
        return true
    }
}

WARNING

面試時可能會被問到是否需要還原鏈結串列。若需要,在比對完成後再反轉一次後半段即可。

🔑 Takeaways