Boolean Array Approach¶
Intuition¶
-
The key idea is to use a boolean array to mark which characters are allowed. Since we're only dealing with lowercase English letters, we need an array of size 26. Each index in the array will correspond to a character based on its ASCII value.
-
Each character has an integer representation called its ASCII value. For example, a has an ASCII value of 97, b is 98, and so on until z, which is 122. We can map each character to an index from 0 to 25 by subtracting the ASCII value of a from the character's ASCII value. For example, c maps to index 2 because the difference between the ASCII values of c (99) and a (97) is 2.
-
With this setup, we can loop through each character in every word and check in constant time whether that character is allowed. If any character's index in our boolean array is false, the word isn't consistent. If all characters are marked true, we increase our counter of consistent words.
Approach¶
Hash set¶
- Initialize a boolean array
seenof size26to store which characters are allowed. -
Iterate through each character in the
allowedstring: -
Mark the corresponding index in
seenas true. -
Initialize a variable
countto store the number of consistent strings. - Initialize a function which named
isConsistentwithwordis parameters and return abooleanvariable: - Iterate through each character in
word:- Check if the current character is allowed by accessing the corresponding index in
seen: - If not allowed, return
falseotherwise we continue to iterate.
- Check if the current character is allowed by accessing the corresponding index in
- return
truewhen meet end of iteration. - Iterate through each
wordin thewordsarray: - if
isConsitent(word)returntrue, incrementcount. - Return the final value of
countas the result.
Bitset¶
- This follow the same principle with the hash set approach, you hash all valid characters into 1 "bucket", but this time instead of an array we use a single variable
mask. - This approach works because the problem don't ask for the frequency and only want us to check the existence of a character. So we can set the position of bits inside
maskbased on the valid character's ASCII value minus'a'(see above for detailed explaination). Also, because there is only 26 lower-case alphabet characters and an int have 32 bits, we can easily fit all characters inside an int variable. - Start with initialize our "bucket"
mask = 0which is an empty bucket with all bit unset. - Iterate the allowed characters list and set the i-th bit of
maskbased on the position of the character in alphabet. Now we have our bucket filled. - Iterate the string list, check every characters of each string and doing comparision:
(mask >> (c-'a'))this code basically move the bits at position (c-'a') to the right most side.(mask >> (c-'a')) & 1this check if the right most side exist or not, if it isn't the result will be 0, otherwise it will be 1bits = (mask >> (c-'a')) & 1will either be 1 or 0 (true or false)
Complexity¶
- Time Complexity: $O(N * M)$, where
Nis the length ofwordsarray, M is maximum length of all words - Space Complexity: $O(26)$ where 26 is the number of English lowercase characters.
- Space Complexity (bitmask): O(1) as the valid chars are hashed into
maskvariable
Code¶
Go¶
func countConsistentStrings(allowed string, words []string) int {
seen := make([]bool, 26)
for _, ch := range allowed {
seen[ch - 'a'] = true
}
count := 0
var isConsistent func(string) bool
isConsistent = func(word string) bool {
for _, ch := range word {
if !seen[ch-'a'] {
return false
}
}
return true
};
for _, word := range words {
if isConsistent(word) {
count++
}
}
return count
}
Java¶
class Solution {
public int countConsistentStrings(String allowed, String[] words) {
boolean[] allowedFreq = new boolean[26];
for (Character c : allowed.toCharArray()) {
allowedFreq[c - 'a'] = true;
}
int result = 0;
for (String word : words) {
if (isConsistent(word, allowedFreq)) {
result += 1;
}
}
return result;
}
private boolean isConsistent(String word, boolean[] allowedFreq) {
for (int i = 0; i < word.length(); ++i) {
if (!allowedFreq[word.charAt(i) - 'a']) {
return false;
}
}
return true;
}
}
C++¶
class Solution {
public:
int countConsistentStrings(string allowed, vector<string>& words) {
int mask = 0;
for(char c : allowed) mask |= 1 << (c - 'a');
int res = 0;
for(auto s : words) {
if(is_valid(s, mask)) res++;
}
return res;
}
bool is_valid(string s, int mask) {
for(char c : s) {
int bit = (mask >> (c - 'a')) & 1;
if(!bit) return false;
}
return true;
}
};