↓快轉到主要內容
  1. LeetCode/

LeetCode 1763: Longest Nice Substring

·1 分鐘· ·
LeetCode Easy Sliding-Window Divide-and-Conquer Hash-Table String Bit-Manipulation
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: easy 第一次嘗試:2026-01-17

  • 提交紀錄:Wrong Answer ×3 → Accepted(滑動視窗)→ Accepted(分治)

解題思路
#

跟 LeetCode 395 是同一類:「每個字母大小寫都出現」不單調。

分治:如果某個字元的另一種大小寫在整個字串裡都沒出現,答案一定不包含它。用它切開,左右兩邊遞迴,取比較長的;一樣長取左邊的(題目要最早出現的)。

n <= 100,直接枚舉所有子字串 O(n^2 · 26) 也可以。

我的嘗試
#

我前四版用 395 的做法:枚舉視窗裡有幾種字母(不分大小寫),固定種類數滑動,再檢查大寫和小寫出現的字母是否一樣。三次 WA 都是移出左邊字元時的更新:

版本問題
第一版某個大小寫的數量歸零時就把種類數減一,但另一種大小寫可能還在視窗裡。例如 s = "AabAAa":答案是 "AAa",回傳 "Aa"
第二版改成兩種都歸零才減種類數,但數量歸零、另一種還在時,key 沒有刪掉,keys() 比較會把數量 0 的 key 也算進去。例如 s = "acAbB":"AbB" 沒有小寫 a,卻被判成合法,答案是 "bB"
第三版比較改成整個 dict 相等,等於要求大寫和小寫的數量也一樣。例如 s = "AaA":答案是 "AaA",回傳 "Aa"
第四版 AC數量歸零就刪 key,另一種也歸零才減種類數

之後改用分治,簡單很多。

正確解法
#

class Solution:
    def longestNiceSubstring(self, s: str) -> str:
        chars = set(s)
        for i, c in enumerate(s):
            if c.swapcase() not in chars:          # c 不可能在答案裡
                left = self.longestNiceSubstring(s[:i])
                right = self.longestNiceSubstring(s[i + 1:])
                return left if len(left) >= len(right) else right   # 一樣長取左邊
        return s

複雜度
#

時間 O(n^2)(每層切一刀,最多 n 層,每層 O(n)),空間 O(n) 遞迴深度。

要特別避免的錯誤
#

  • 長度相同時要取最早出現的。
  • 用 dict.keys() 比較時,數量歸零的 key 要刪掉。

面試口說整理
#

如果某個字元的另一種大小寫在字串裡都沒有,它一定不在答案裡,所以我用它把字串切開,左右遞迴,取比較長的,一樣長取左邊。所有字元都有配對時整段就是答案。n 只有 100,最壞 O(n^2) 沒問題。

相關文章

LeetCode 395: Longest Substring with At Least K Repeating Characters
·2 分鐘
LeetCode Medium Sliding-Window Divide-and-Conquer Hash-Table String
LeetCode 395 解題筆記:「每個字元至少 k 次」不單調,不能直接滑動;分治法用出現不到 k 次的字元切開,或枚舉視窗裡有幾種字元,固定種類數後就能滑動
LeetCode 1016: Binary String With Substrings Representing 1 To N
·2 分鐘
LeetCode Medium Sliding-Window String Bit-Manipulation Hash-Table
LeetCode 1016 解題筆記:s 最多 1000 個字元,長度固定時的子字串數量有限,n 太大一定是 False;從 n 往下檢查會很快失敗,或從每個起點往右最多延伸 30 位收集所有 <= n 的值
LeetCode 187: Repeated DNA Sequences
·1 分鐘
LeetCode Medium Hash-Table String Bit-Manipulation Sliding-Window
LeetCode 187 解題筆記:把每個長度 10 的子字串丟進雜湊表計數,出現超過一次的就是答案
LeetCode 389: Find the Difference
·1 分鐘
LeetCode Easy Hash-Table String Bit-Manipulation Sorting
LeetCode 389 解題筆記:t 比 s 多一個字元,把兩個字串的所有字元 XOR 起來,成對的抵消,剩下的就是多的那個
LeetCode 3090: Maximum Length Substring With Two Occurrences
·1 分鐘
LeetCode Easy Sliding-Window Hash-Table String
LeetCode 3090 解題筆記:「求最長」的滑動視窗,剛加進來的字元超過 2 次就縮左邊
LeetCode 2781: Length of the Longest Valid Substring
·2 分鐘
LeetCode Hard Sliding-Window Hash-Table String Trie
LeetCode 2781 解題筆記:禁字最長只有 10,每個右端只檢查最後 10 個字元組成的後綴;找到禁字就把左端推到它後面,要找最短的那個(最靠右的起點)