Easy草稿★★★★★O(n) 時間 · O(1) 空間
Two PointersStringGreedy
Patterns↔️ 雙指針🪙 貪心
尚未複習過

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

680Valid Palindrome IITwo PointersEasyTwo Pointers

給定字串 s,判斷最多刪除一個字元後,是否能成為回文。

Example:

Input: s = “abca” Output: true(刪除 ‘b’ 或 ‘c’ 後為回文)

Intuition

TIP

核心思路:雙指針從兩端往中間比對,遇到不同時嘗試跳過左或右其中一個字元,檢查剩餘部分是否為回文。

Approaches

1. Brute Force - Try Removing Each Char — O(n²) / O(n)
  • Idea: 對每個位置 i,刪除 s[i] 後檢查剩餘字串是否回文
  • Time: O(n²) - n 個位置各檢查 O(n)
  • Space: O(n) - 建立子字串
Brute Force Code
class Solution {
    fun validPalindrome(s: String): Boolean {
        for (i in s.indices) {
            val t = s.removeRange(i, i + 1)
            if (t == t.reversed()) return true
        }
        return s == s.reversed()
    }
}
⭐ 2. Two Pointers + Greedy Skip — O(n) / O(1)
  • Idea: 左右指針比對,遇到不匹配時分別嘗試跳過左或右,檢查子區間是否回文
  • Time: O(n) - 主迴圈 + 子區間檢查合計最多遍歷一次
  • Space: O(1) - 只用指針
class Solution {
    fun validPalindrome(s: String): Boolean {
        var left = 0
        var right = s.length - 1

        while (left < right) {
            if (s[left] != s[right]) {
                return isPalindrome(s, left + 1, right) ||
                       isPalindrome(s, left, right - 1)
            }
            left++
            right--
        }
        return true
    }

    private fun isPalindrome(s: String, l: Int, r: Int): Boolean {
        var left = l
        var right = r
        while (left < right) {
            if (s[left] != s[right]) return false
            left++
            right--
        }
        return true
    }
}

WARNING

遇到不匹配時必須同時嘗試兩種跳過方向,只嘗試一邊可能漏掉正確答案。例如 "cupucu" 需要跳右邊才正確。

🔑 Takeaways