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

LeetCode 3703: Remove K-Balanced Substrings

·2 分鐘· ·
LeetCode Medium Stack String Simulation
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2025-10-05

  • 提交紀錄:Accepted(5298ms)

解題思路
#

k 平衡的子字串是 k 個 ( 接著 k 個 )。要一直刪掉這種子字串,直到沒有為止。

刪掉一段之後,左右兩邊會接起來,可能又形成新的 k 平衡子字串。這種「刪掉後跟前面接起來」的模式,就是 stack。

我的解法:反覆 replace
#

class Solution:
    def removeSubstring(self, s: str, k: int) -> str:
        target = "(" * k + ")" * k
        while target in s:
            s = s.replace(target, "", 1)
        return s

AC 了,但跑了 5298ms。每次 in 和 replace 都要重新掃整個字串,最多要刪 n / 2k 次,總共 O(n^2 / k)。

更好的解法:stack 存連續段
#

stack 裡存 [字元, 連續個數],相同字元就合併到同一段:

  1. 讀到一個字元,如果跟頂端那段相同就個數加 1,否則開新的一段。
  2. 如果頂端是 ) 而且剛好 k 個,下面那段是 ( 而且至少 k 個,就把這 k 個 ) 和 k 個 ( 一起消掉。
  3. ( 那段被消到 0 就整段移除,之後讀進來的字元會自動跟新的頂端合併。
class Solution:
    def removeSubstring(self, s: str, k: int) -> str:
        stack = []                                 # [字元, 連續個數]
        for ch in s:
            if stack and stack[-1][0] == ch:
                stack[-1][1] += 1
            else:
                stack.append([ch, 1])
            if (ch == ")" and stack[-1][1] == k and len(stack) >= 2
                    and stack[-2][0] == "(" and stack[-2][1] >= k):
                stack.pop()
                stack[-1][1] -= k
                if stack[-1][1] == 0:
                    stack.pop()
        return "".join(ch * cnt for ch, cnt in stack)

只在 ) 的個數剛好等於 k 時檢查:個數超過 k 代表前面的 ( 不夠,之後再多的 ) 也湊不出來。

複雜度
#

解法時間
反覆 replaceO(n^2 / k)
stack 存連續段O(n)

要特別避免的錯誤
#

  • 只刪一輪就停:刪掉之後左右接起來可能又形成新的 k 平衡子字串。
  • stack 存單一字元:每次都要往回數 k 個,最壞會變慢;存連續段的個數就不用。

面試口說整理
#

刪掉一段之後左右會接起來,可能又能刪,所以用 stack。我讓 stack 存每段連續相同字元和它的個數,讀到 ) 且這段剛好 k 個、下面的 ( 段至少 k 個時,就把這兩段各減 k,空了就移除。每個字元只進出一次,時間 O(n)。原本反覆用 replace 雖然能過,但每次都重掃整個字串。

相關文章

LeetCode 3612: Process String with Special Operations I
·1 分鐘
LeetCode Medium String Simulation
LeetCode 3612 解題筆記:用 list 模擬四種操作;判斷 * 時要把「結果非空」寫在分支裡面,不然 * 會被當成字母加進去
LeetCode 735: Asteroid Collision
·1 分鐘
LeetCode Medium Array Stack Simulation
LeetCode 735 解題筆記:從左到右用 stack,只有「stack 頂端往右、目前的往左」才會相撞,小的爆掉,一樣大一起爆
LeetCode 402: Remove K Digits
·1 分鐘
LeetCode Medium String Stack Greedy Monotonic-Stack
LeetCode 402 解題筆記:單調遞增 stack,遇到比頂端小的數字就把頂端刪掉(還有 k 次可刪時),最後去掉前導零
LeetCode 227: Basic Calculator II
·1 分鐘
LeetCode Medium Math String Stack
LeetCode 227 解題筆記:先把數字讀完整,遇到運算子時處理上一個運算子:+ - 把數放進 stack(減號放負數),* / 直接跟頂端算
LeetCode 71: Simplify Path
·1 分鐘
LeetCode Medium String Stack
LeetCode 71 解題筆記:用 / 切開,空字串和 . 跳過,.. 就 pop(根目錄不能再往上),其他名稱 push,最後用 / 接起來
LeetCode 43: Multiply Strings
·1 分鐘
LeetCode Medium Math String Simulation
LeetCode 43 解題筆記:num1[i] × num2[j] 的結果落在第 i + j + 1 位,用一個長度 n + m 的陣列累加後再統一進位