Before attempting this problem, you should be comfortable with:
Hash Sets - Storing and checking unique substrings efficiently
Sliding Window - Processing fixed-size windows over a string without redundant computation
Bit Manipulation - Using bitwise operations to represent binary strings as integers
Binary Number Representation - Converting between binary strings and decimal integers
1. Brute Force
Intuition
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 2k such binary codes (from 0 to 2k−1), and we need to verify that every single one appears somewhere in s.
Algorithm
If the length of s is less than 2k, return false immediately since there cannot be enough substrings.
Iterate through all numbers from 0 to 2k−1.
For each number, convert it to its binary representation with exactly k digits (padding with leading zeros if needed).
Check if this binary string exists as a substring in s.
classSolution:defhasAllCodes(self, s:str, k:int)->bool:
n =len(s)if n <(1<< k):returnFalsefor num inrange(1<< k):
binaryCode =format(num,f'0{k}b')if binaryCode notin s:returnFalsereturnTrue
publicclassSolution{publicbooleanhasAllCodes(String s,int k){int n = s.length();if(n <(1<< k)){returnfalse;}for(int num =0; num <(1<< k); num++){String binaryCode =String.format("%"+ k +"s",Integer.toBinaryString(num)).replace(' ','0');if(!s.contains(binaryCode)){returnfalse;}}returntrue;}}
classSolution{public:boolhasAllCodes(string s,int k){int n = s.size();if(n <(1<< k)){returnfalse;}for(int num =0; num <(1<< k); num++){
string binaryCode =bitset<20>(num).to_string().substr(20- k);if(s.find(binaryCode)== string::npos){returnfalse;}}returntrue;}};
classSolution{/**
* @param {string} s
* @param {number} k
* @return {boolean}
*/hasAllCodes(s, k){const n = s.length;if(n <1<< k){returnfalse;}for(let num =0; num <1<< k; num++){const binaryCode = num.toString(2).padStart(k,'0');if(!s.includes(binaryCode)){returnfalse;}}returntrue;}}
publicclassSolution{publicboolHasAllCodes(string s,int k){int n = s.Length;if(n <(1<< k)){returnfalse;}for(int num =0; num <(1<< k); num++){string binaryCode = Convert.ToString(num,2).PadLeft(k,'0');if(!s.Contains(binaryCode)){returnfalse;}}returntrue;}}
funchasAllCodes(s string, k int)bool{
n :=len(s)if n <(1<< k){returnfalse}for num :=0; num <(1<< k); num++{
binaryCode := fmt.Sprintf("%0*b", k, num)if!strings.Contains(s, binaryCode){returnfalse}}returntrue}
class Solution {funhasAllCodes(s: String, k: Int): Boolean {val n = s.length
if(n <(1shl k)){returnfalse}for(num in0until(1shl k)){val binaryCode = num.toString(2).padStart(k,'0')if(!s.contains(binaryCode)){returnfalse}}returntrue}}
classSolution{funchasAllCodes(_ s:String,_ k:Int)->Bool{let n = s.count
if n <(1<< k){returnfalse}for num in0..<(1<< k){let binaryCode =String(num, radix:2).paddingLeft(toLength: k, withPad:"0")if!s.contains(binaryCode){returnfalse}}returntrue}}extensionString{funcpaddingLeft(toLength:Int, withPad:String)->String{let padding =String(repeating: withPad, count:max(0, toLength -self.count))return padding +self}}
Time & Space Complexity
Time complexity: O(n∗2k)
Space complexity: O(k)
Where n is the length of the string s and k is the length of the binary code.
2. Hash Set
Intuition
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 2k unique substrings, then all binary codes are present. This is more efficient because we process each substring only once.
Algorithm
If the length of s is less than 2k, return false immediately.
Create an empty hash set to store unique substrings.
Iterate through s and extract every substring of length k.
Add each substring to the hash set.
After processing all substrings, check if the set size equals 2k.
Return true if the count matches, false otherwise.
classSolution:defhasAllCodes(self, s:str, k:int)->bool:iflen(s)<2** k:returnFalse
codeSet =set()for i inrange(len(s)- k +1):
codeSet.add(s[i:i + k])returnlen(codeSet)==2** k
publicclassSolution{publicbooleanhasAllCodes(String s,int k){if(s.length()<(1<< k)){returnfalse;}HashSet<String> codeSet =newHashSet<>();for(int i =0; i <= s.length()- k; i++){
codeSet.add(s.substring(i, i + k));}return codeSet.size()==(1<< k);}}
classSolution{public:boolhasAllCodes(std::string s,int k){if(s.size()<(1<< k)){returnfalse;}
std::unordered_set<std::string> codeSet;for(int i =0; i <= s.size()- k; i++){
codeSet.insert(s.substr(i, k));}return codeSet.size()==(1<< k);}};
classSolution{/**
* @param {string} s
* @param {number} k
* @return {boolean}
*/hasAllCodes(s, k){if(s.length <1<< k){returnfalse;}const codeSet =newSet();for(let i =0; i <= s.length - k; i++){
codeSet.add(s.substring(i, i + k));}return codeSet.size ===1<< k;}}
publicclassSolution{publicboolHasAllCodes(string s,int k){if(s.Length <(1<< k)){returnfalse;}HashSet<string> codeSet =newHashSet<string>();for(int i =0; i <= s.Length - k; i++){
codeSet.Add(s.Substring(i, k));}return codeSet.Count ==(1<< k);}}
funchasAllCodes(s string, k int)bool{iflen(s)<(1<< k){returnfalse}
codeSet :=make(map[string]bool)for i :=0; i <=len(s)-k; i++{
codeSet[s[i:i+k]]=true}returnlen(codeSet)==(1<< k)}
Where n is the length of the string s and k is the length of the binary code.
3. Sliding Window
Intuition
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.
Algorithm
If the length of s is less than 2k, return false.
Create a boolean array of size 2k to track which codes have been seen.
Build the initial window by reading the first k characters and converting them to an integer using bit shifts.
Mark the first code as seen and initialize a counter.
Slide the window one character at a time:
Remove the leftmost bit using XOR if it was 1.
Shift the current value left by 1.
Add the new rightmost bit using OR.
If this code has not been seen before, mark it and increment the counter.
classSolution:defhasAllCodes(self, s:str, k:int)->bool:
n =len(s)if n <(1<< k):returnFalse
codeSet =[False]*(1<< k)
cur =0
i = j =0
bit = k -1while j < k:if s[j]=='1':
cur |=(1<< bit)
bit -=1
j +=1
have =1
codeSet[cur]=Truewhile j < n:if s[i]=='1':
cur ^=(1<<(k -1))
i +=1
cur <<=1if s[j]=='1':
cur |=1
j +=1ifnot codeSet[cur]:
have +=1
codeSet[cur]=Truereturn have ==(1<< k)
publicclassSolution{publicbooleanhasAllCodes(String s,int k){int n = s.length();if(n <(1<< k)){returnfalse;}boolean[] codeSet =newboolean[1<< k];int cur =0;int i =0, j =0, bit = k -1;while(j < k){if(s.charAt(j)=='1'){
cur |=(1<< bit);}
bit--;
j++;}int have =1;
codeSet[cur]=true;while(j < n){if(s.charAt(i)=='1'){
cur ^=(1<<(k -1));}
i++;
cur <<=1;if(s.charAt(j)=='1'){
cur |=1;}
j++;if(!codeSet[cur]){
have++;
codeSet[cur]=true;}}return have ==(1<< k);}}
classSolution{public:boolhasAllCodes(string s,int k){int n = s.size();if(n <(1<< k)){returnfalse;}
vector<bool>codeSet(1<< k,false);int cur =0;int i =0, j =0, bit = k -1;while(j < k){if(s[j]=='1'){
cur |=(1<< bit);}
bit--;
j++;}int have =1;
codeSet[cur]=true;while(j < n){if(s[i]=='1'){
cur ^=(1<<(k -1));}
i++;
cur <<=1;if(s[j]=='1'){
cur |=1;}
j++;if(!codeSet[cur]){
have++;
codeSet[cur]=true;}}return have ==(1<< k);}};
classSolution{/**
* @param {string} s
* @param {number} k
* @return {boolean}
*/hasAllCodes(s, k){const n = s.length;if(n <1<< k){returnfalse;}const codeSet =newArray(1<< k).fill(false);let cur =0;let i =0,
j =0,
bit = k -1;while(j < k){if(s[j]==='1'){
cur |=1<< bit;}
bit--;
j++;}let have =1;
codeSet[cur]=true;while(j < n){if(s[i]==='1'){
cur ^=1<<(k -1);}
i++;
cur <<=1;if(s[j]==='1'){
cur |=1;}
j++;if(!codeSet[cur]){
have++;
codeSet[cur]=true;}}return have ===1<< k;}}
publicclassSolution{publicboolHasAllCodes(string s,int k){int n = s.Length;if(n <(1<< k)){returnfalse;}bool[] codeSet =newbool[1<< k];int cur =0;int i =0, j =0, bit = k -1;while(j < k){if(s[j]=='1'){
cur |=(1<< bit);}
bit--;
j++;}int have =1;
codeSet[cur]=true;while(j < n){if(s[i]=='1'){
cur ^=(1<<(k -1));}
i++;
cur <<=1;if(s[j]=='1'){
cur |=1;}
j++;if(!codeSet[cur]){
have++;
codeSet[cur]=true;}}return have ==(1<< k);}}
funchasAllCodes(s string, k int)bool{
n :=len(s)if n <(1<< k){returnfalse}
codeSet :=make([]bool,1<<k)
cur :=0
i, j, bit :=0,0, k-1for j < k {if s[j]=='1'{
cur |=(1<< bit)}
bit--
j++}
have :=1
codeSet[cur]=truefor j < n {if s[i]=='1'{
cur ^=(1<<(k -1))}
i++
cur <<=1if s[j]=='1'{
cur |=1}
j++if!codeSet[cur]{
have++
codeSet[cur]=true}}return have ==(1<< k)}
class Solution {funhasAllCodes(s: String, k: Int): Boolean {val n = s.length
if(n <(1shl k)){returnfalse}val codeSet =BooleanArray(1shl k)var cur =0var i =0var j =0var bit = k -1while(j < k){if(s[j]=='1'){
cur = cur or(1shl bit)}
bit--
j++}var have =1
codeSet[cur]=truewhile(j < n){if(s[i]=='1'){
cur = cur xor(1shl(k -1))}
i++
cur = cur shl1if(s[j]=='1'){
cur = cur or1}
j++if(!codeSet[cur]){
have++
codeSet[cur]=true}}return have ==(1shl k)}}
classSolution{funchasAllCodes(_ s:String,_ k:Int)->Bool{let n = s.count
if n <(1<< k){returnfalse}let arr =Array(s)var codeSet =[Bool](repeating:false, count:1<< k)var cur =0var i =0, j =0, bit = k -1while j < k {if arr[j]=="1"{
cur |=(1<< bit)}
bit -=1
j +=1}var have =1
codeSet[cur]=truewhile j < n {if arr[i]=="1"{
cur ^=(1<<(k -1))}
i +=1
cur <<=1if arr[j]=="1"{
cur |=1}
j +=1if!codeSet[cur]{
have +=1
codeSet[cur]=true}}return have ==(1<< k)}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(2k)
Where n is the length of the string s and k is the length of the binary code.
4. Sliding Window (Optimal)
Intuition
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 (2k−1) after shifting. This mask keeps only the rightmost k bits, effectively removing any bits that overflow beyond the window size.
Algorithm
If the length of s is less than 2k, return false.
Create a boolean array of size 2k to track seen codes.
Initialize the current code value and a counter for unique codes found.
Iterate through each character in s:
Shift the current value left by 1.
Apply a bitmask (AND with 2k−1) to keep only the last k bits.
Add the current character's bit value using OR.
Once we have processed at least k characters, check if this code is new.
If new, mark it as seen and increment the counter.
classSolution:defhasAllCodes(self, s:str, k:int)->bool:
n =len(s)if n <(1<< k):returnFalse
codeSet =[False]*(1<< k)
cur =0
have =0for i inrange(n):
cur =((cur <<1)&((1<< k)-1))|(ord(s[i])-ord('0'))if i >= k -1:ifnot codeSet[cur]:
codeSet[cur]=True
have +=1return have ==(1<< k)
publicclassSolution{publicbooleanhasAllCodes(String s,int k){int n = s.length();if(n <(1<< k)){returnfalse;}boolean[] codeSet =newboolean[1<< k];int cur =0, have =0;for(int i =0; i < n; i++){
cur =((cur <<1)&((1<< k)-1))|(s.charAt(i)-'0');if(i >= k -1){if(!codeSet[cur]){
codeSet[cur]=true;
have++;}}}return have ==(1<< k);}}
classSolution{public:boolhasAllCodes(string s,int k){int n = s.size();if(n <(1<< k)){returnfalse;}
vector<bool>codeSet(1<< k,false);int cur =0, have =0;for(int i =0; i < n; i++){
cur =((cur <<1)&((1<< k)-1))|(s[i]-'0');if(i >= k -1){if(!codeSet[cur]){
codeSet[cur]=true;
have++;}}}return have ==(1<< k);}};
classSolution{/**
* @param {string} s
* @param {number} k
* @return {boolean}
*/hasAllCodes(s, k){const n = s.length;if(n <1<< k){returnfalse;}const codeSet =newArray(1<< k).fill(false);let cur =0,
have =0;for(let i =0; i < n; i++){
cur =((cur <<1)&((1<< k)-1))|(s[i]-'0');if(i >= k -1){if(!codeSet[cur]){
codeSet[cur]=true;
have++;}}}return have ===1<< k;}}
publicclassSolution{publicboolHasAllCodes(string s,int k){int n = s.Length;if(n <(1<< k)){returnfalse;}bool[] codeSet =newbool[1<< k];int cur =0, have =0;for(int i =0; i < n; i++){
cur =((cur <<1)&((1<< k)-1))|(s[i]-'0');if(i >= k -1){if(!codeSet[cur]){
codeSet[cur]=true;
have++;}}}return have ==(1<< k);}}
funchasAllCodes(s string, k int)bool{
n :=len(s)if n <(1<< k){returnfalse}
codeSet :=make([]bool,1<<k)
cur, have :=0,0for i :=0; i < n; i++{
cur =((cur <<1)&((1<< k)-1))|int(s[i]-'0')if i >= k-1{if!codeSet[cur]{
codeSet[cur]=true
have++}}}return have ==(1<< k)}
class Solution {funhasAllCodes(s: String, k: Int): Boolean {val n = s.length
if(n <(1shl k)){returnfalse}val codeSet =BooleanArray(1shl k)var cur =0var have =0for(i in0 until n){
cur =((cur shl1)and((1shl k)-1))or(s[i]-'0')if(i >= k -1){if(!codeSet[cur]){
codeSet[cur]=true
have++}}}return have ==(1shl k)}}
classSolution{funchasAllCodes(_ s:String,_ k:Int)->Bool{let n = s.count
if n <(1<< k){returnfalse}let arr =Array(s)var codeSet =[Bool](repeating:false, count:1<< k)var cur =0, have =0for i in0..<n {
cur =((cur <<1)&((1<< k)-1))|(arr[i]=="1"?1:0)if i >= k -1{if!codeSet[cur]{
codeSet[cur]=true
have +=1}}}return have ==(1<< k)}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(2k)
Where n is the length of the string s and k is the length of the binary code.
Common Pitfalls
Forgetting the Early Length Check
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:iflen(s)<(1<< k):returnFalse
Off-by-One Error in Substring Extraction
When 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 inrange(len(s)- k +1):
codeSet.add(s[i:i + k])
Incorrect Bitmask in Sliding Window
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