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

LeetCode 1016: Binary String With Substrings Representing 1 To N

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

基本資料
#

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

  • 提交紀錄:Memory Limit Exceeded → Wrong Answer ×4 → Accepted

解題思路
#

n 可以到 10^9,但 s 最多只有 1000 個字元。

關鍵觀察:(n/2, n] 裡的數字二進位長度都一樣,設為 L,共約 n/2 個。s 裡長度 L 的子字串最多只有 len(s) 個,所以只要 n/2 > len(s),一定有數字找不到。也就是說,答案是 True 的時候 n 一定很小(大約 <= 2000)。

兩種做法:

  1. 從 n 往下檢查:每個數字用 bin(i)[2:] in s 檢查。n 很大時,前面幾個就會失敗;n 小時總共也只檢查幾千次。
  2. 滑動視窗收集:從 s 的每個 1 開始往右延伸,邊走邊算二進位值,超過 n 或超過 30 位就停,把所有 <= n 的值放進 set,最後看 set 的大小是不是 n。

我的嘗試
#

版本問題
第一版 MLE先把 1..n 的二進位字串全部放進 set,n = 10^9 時記憶體爆掉
第二版 WA改成「每個長度的子字串種類數要夠多」,長度 1 要求 "0"、"1" 兩種都有。但 0 不在 1..n 裡。例如 s = "1"、n = 1:答案是 True,這版回傳 False
第三到五版 WA改成長度 w 要有 2^w - 1 種。但子字串可能有前導 0("0"、"01"),而且 n 不一定用到長度 w 的所有數字,數量對不代表內容對。例如 s = "0"、n = 1:長度 1 的種類數是 1,但那是 "0" 不是 "1",答案是 False,這版回傳 True
AC直接從 n 往下用 in 檢查每個數字

正確解法
#

class Solution:
    def queryString(self, s: str, n: int) -> bool:
        for i in range(n, 0, -1):                  # 大的數字先檢查,n 太大會很快失敗
            if bin(i)[2:] not in s:
                return False
        return True

滑動視窗收集的版本:

class Solution:
    def queryString(self, s: str, n: int) -> bool:
        seen = set()
        for i in range(len(s)):
            if s[i] == "0":
                continue                           # 二進位表示不會有前導 0
            val = 0
            for j in range(i, min(len(s), i + 30)):
                val = val * 2 + (s[j] == "1")
                if val > n:
                    break
                seen.add(val)
        return len(seen) == n

複雜度
#

  • 往下檢查:答案是 True 時 n = O(len(s)),每次 in 是 O(len(s) · log n),總共大約 O(len(s)^2 · log n);n 很大時會在前幾個數字就失敗。
  • 收集版本:時間 O(30 · len(s)),空間 O(min(n, 30 · len(s)))。

要特別避免的錯誤
#

  • 把 1..n 全部存起來:n 可以到 10^9。
  • 用「子字串種類數」判斷:前導 0 和不在 1..n 範圍的值都會混進來。

面試口說整理
#

s 最多 1000 個字元,而 n/2 到 n 之間的數字二進位長度都一樣,所以 n 大於大約兩倍的 len(s) 時一定是 False。我可以從 n 往下檢查每個數字是不是子字串,n 大時很快就會失敗;或者從每個 1 開始往右最多延伸 30 位,把所有 <= n 的值收進 set,看大小是不是 n,時間 O(30 · len(s))。

相關文章

LeetCode 187: Repeated DNA Sequences
·1 分鐘
LeetCode Medium Hash-Table String Bit-Manipulation Sliding-Window
LeetCode 187 解題筆記:把每個長度 10 的子字串丟進雜湊表計數,出現超過一次的就是答案
LeetCode 3694: Distinct Points Reachable After Substring Removal
·1 分鐘
LeetCode Medium Sliding-Window Prefix-Sum Hash-Table String
LeetCode 3694 解題筆記:終點 = 全部的位移 − 被刪掉那段的位移;用長度 k 的視窗維護那段的位移,把每個終點放進 set
LeetCode 424: Longest Repeating Character Replacement
·1 分鐘
LeetCode Medium Hash-Table String Sliding-Window
LeetCode 424 解題筆記:可變長度滑動視窗,視窗長度減掉最多的字元次數就是要替換的數量,超過 k 就縮左邊
LeetCode 2953: Count Complete Substrings
·2 分鐘
LeetCode Hard Sliding-Window Hash-Table String
LeetCode 2953 解題筆記:先在相鄰字元差 > 2 的地方切段;每段枚舉有幾種字元 d,視窗長度固定是 d × k,維護「剛好出現 k 次的字元數」
LeetCode 1888: Minimum Number of Flips to Make the Binary String Alternating
·1 分鐘
LeetCode Medium Sliding-Window String Dynamic-Programming
LeetCode 1888 解題筆記:把移到尾巴的操作變成在 s + s 上滑動長度 n 的視窗;視窗跟 0101… 不同的數量是 diff,跟 1010… 不同的就是 n - diff
LeetCode 3795: Minimum Subarray Length With Distinct Sum At Least K
·1 分鐘
LeetCode Medium Sliding-Window Hash-Table Array
LeetCode 3795 解題筆記:求最短的可變視窗;同一個值只算一次,記錄每個值最後出現的位置,左邊界移出的是最後一次出現才扣掉