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

LeetCode 3306: Count of Substrings Containing Every Vowel and K Consonants II

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

基本資料
#

難易度: medium 第一次嘗試:2026-01-21

  • 提交紀錄:Wrong Answer ×2 → Accepted → Runtime Error → Accepted

解題思路
#

「剛好 k 個子音」不單調。但「五個母音都有、子音至少 m 個」是單調的(視窗變大只會更容易滿足),所以:

剛好 k 個 = 至少 k 個 − 至少 k + 1 個

「至少」型的計數:合法時一直縮左邊,縮到不合法,count += left。

我的嘗試
#

我的寫法是另一種思路:子音數固定是 k 的時候,左邊多出來的母音可以拿掉也可以留著,用 extra 記錄「左邊還可以多拿掉幾個母音」,每個右端加 1 + extra。

版本問題
第一版每個右端只加 1,沒算左邊可以多放的母音。例如 word = "euioeaa"、k = 0:答案是 4,回傳 2
第二版加上 extra,但它是每一輪重新從 0 開始的區域變數。左邊的多餘母音在前幾輪已經被拿掉了,這輪就算不到。同一個例子回傳 3
ACextra 移到迴圈外,只在子音太多、必須縮掉子音時才歸零
RE重寫時把 extra = 0 放在縮子音的迴圈裡,沒縮的時候 extra 根本沒定義,UnboundLocalError
AC初始化移回迴圈外

extra 的做法是對的,但要想清楚什麼時候歸零;「至少」相減的做法不需要額外狀態。

正確解法
#

class Solution:
    def countOfSubstrings(self, word: str, k: int) -> int:
        def at_least(m: int) -> int:               # 五個母音都有、子音至少 m 個
            vowels = Counter()
            consonants = left = count = 0
            for c in word:
                if c in "aeiou":
                    vowels[c] += 1
                else:
                    consonants += 1
                while len(vowels) == 5 and consonants >= m:
                    d = word[left]
                    if d in "aeiou":
                        vowels[d] -= 1
                        if vowels[d] == 0:
                            del vowels[d]
                    else:
                        consonants -= 1
                    left += 1
                count += left
            return count

        return at_least(k) - at_least(k + 1)

複雜度
#

時間 O(n),空間 O(1)。

要特別避免的錯誤
#

  • 「剛好」直接滑:不單調,左邊多餘的母音會漏算。
  • 用 extra 的寫法時,它只能在子音被移出時歸零。

面試口說整理
#

「剛好 k 個子音」不單調,所以我改成「至少 k 個」減「至少 k + 1 個」。「五個母音都有而且子音至少 m 個」是單調的,用「至少」型的滑動視窗:合法時一直縮左邊,左端在 0 到 left - 1 都合法,加上 left。時間 O(n)。

相關文章

LeetCode 1358: Number of Substrings Containing All Three Characters
·1 分鐘
LeetCode Medium Sliding-Window Hash-Table String
LeetCode 1358 解題筆記:「至少各一個 a、b、c」的計數視窗:三種都有時一直縮左邊,count += left
LeetCode 3325: Count Substrings With K-Frequency Characters I
·1 分鐘
LeetCode Medium Sliding-Window Hash-Table String
LeetCode 3325 解題筆記:「至少一個字元出現 k 次」的計數視窗;剛加入的字元湊滿 k 次就一直縮,縮到它變成 k - 1 次為止
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 2516: Take K of Each Character From Left and Right
·1 分鐘
LeetCode Medium Sliding-Window Hash-Table String
LeetCode 2516 解題筆記:從兩端拿等於中間留一段;留下的每種字元最多是總數 − 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 3694: Distinct Points Reachable After Substring Removal
·1 分鐘
LeetCode Medium Sliding-Window Prefix-Sum Hash-Table String
LeetCode 3694 解題筆記:終點 = 全部的位移 − 被刪掉那段的位移;用長度 k 的視窗維護那段的位移,把每個終點放進 set