The most straightforward approach is to generate all possible binary codes of length k and check if each one exists as a substring in the given string s. There are exactly such binary codes (from 0 to ), and we need to verify that every single one appears somewhere in s.
s is less than , return false immediately since there cannot be enough substrings.0 to .k digits (padding with leading zeros if needed).s.false.true.Where is the length of the string and is the length of the binary code.
Instead of checking each possible binary code one by one, we can flip the approach: extract all substrings of length k from s and store them in a set. If the set contains exactly unique substrings, then all binary codes are present. This is more efficient because we process each substring only once.
s is less than , return false immediately.s and extract every substring of length k.true if the count matches, false otherwise.Where is the length of the string and is the length of the binary code.
We can improve upon the hash set approach by using bit manipulation to represent each substring as an integer. Instead of storing strings, we maintain a sliding window of k bits. As we move through the string, we update the integer representation by removing the leftmost bit and adding the new rightmost bit. This converts string operations into faster bitwise operations.
s is less than , return false.k characters and converting them to an integer using bit shifts.1.1.true if the counter equals .class Solution:
def hasAllCodes(self, s: str, k: int) -> bool:
n = len(s)
if n < (1 << k):
return False
codeSet = [False] * (1 << k)
cur = 0
i = j = 0
bit = k - 1
while j < k:
if s[j] == '1':
cur |= (1 << bit)
bit -= 1
j += 1
have = 1
codeSet[cur] = True
while j < n:
if s[i] == '1':
cur ^= (1 << (k - 1))
i += 1
cur <<= 1
if s[j] == '1':
cur |= 1
j += 1
if not codeSet[cur]:
have += 1
codeSet[cur] = True
return have == (1 << k)Where is the length of the string and is the length of the binary code.
This approach simplifies the sliding window technique by using a bitmask to automatically handle the window size. Instead of explicitly removing the leftmost bit, we use a bitwise AND with a mask () after shifting. This mask keeps only the rightmost k bits, effectively removing any bits that overflow beyond the window size.
s is less than , return false.s:1.k bits.k characters, check if this code is new.true if the counter equals .class Solution:
def hasAllCodes(self, s: str, k: int) -> bool:
n = len(s)
if n < (1 << k):
return False
codeSet = [False] * (1 << k)
cur = 0
have = 0
for i in range(n):
cur = ((cur << 1) & ((1 << k) - 1)) | (ord(s[i]) - ord('0'))
if i >= k - 1:
if not codeSet[cur]:
codeSet[cur] = True
have += 1
return have == (1 << k)Where is the length of the string and is the length of the binary code.
If the string length is less than k + 2^k - 1, it's impossible to contain all binary codes since there aren't enough substrings. Skipping this check leads to unnecessary computation and potential incorrect results.
# Always check first:
if len(s) < (1 << k):
return FalseWhen iterating to extract substrings of length k, the loop should go from 0 to len(s) - k inclusive. Using range(len(s) - k) instead of range(len(s) - k + 1) misses the last valid substring.
# Wrong: for i in range(len(s) - k)
# Correct:
for i in range(len(s) - k + 1):
codeSet.add(s[i:i + k])When using the sliding window approach with bit manipulation, forgetting to mask the result after shifting causes the integer to grow beyond k bits. The mask (1 << k) - 1 must be applied to keep only the last k bits.
# Wrong: cur = (cur << 1) | bit
# Correct:
cur = ((cur << 1) & ((1 << k) - 1)) | bit