Count the Number of Consistent Strings: Set Membership Patterns
You are given a string allowed consisting of distinct characters and an array of strings words. A string is consistent if every character in that string appears in allowed. Return the number of consistent strings in the words array.
This is LeetCode 1684: Count the Number of Consistent Strings, and it is a clean exercise in set membership checking. The problem boils down to one question per word: does every character belong to the allowed set?
Why this problem matters
Count the Number of Consistent Strings isolates one of the most common building blocks in string and array problems: checking whether elements belong to a specific set. You will see this pattern everywhere, from filtering valid inputs to validating constraints in more complex problems. Hash sets give you O(1) membership tests, turning what could be a slow nested loop into a linear scan.
This problem also introduces you to the idea of preprocessing. By converting the allowed string into a set up front, every subsequent character check becomes constant time. That preprocessing step is a pattern you will use repeatedly in problems involving frequency counting, anagram detection, and substring validation.
The key insight
Convert the allowed string into a set. Then for each word, check whether every character in that word is in the set. If all characters pass, the word is consistent. Count up the consistent words.
The set gives you O(1) lookup per character. Without it, you would need to scan through the allowed string for every character of every word, turning an O(n * m) solution into O(n * m * k) where k is the length of allowed. The set eliminates that inner loop entirely.
The solution
def count_consistent_strings(allowed: str, words: list[str]) -> int:
allowed_set = set(allowed)
return sum(
all(ch in allowed_set for ch in word)
for word in words
)
We convert allowed into a set for O(1) lookups. Then we iterate through each word and use Python's all() function with a generator expression to check every character. The all() call short-circuits: as soon as it finds a character not in the set, it stops checking the rest of that word. Finally, sum() counts how many words returned True from the all() check.
You can also solve this with a bitmask instead of a set. Since allowed contains only lowercase English letters, you can represent it as a 26-bit integer where each bit corresponds to a letter. Character membership becomes a bitwise AND operation. The set approach is clearer and preferred in interviews, but the bitmask approach is worth knowing for problems where you need to compare multiple allowed sets efficiently.
Visual walkthrough
Step 0: Build the allowed set
Convert the allowed string "ab" into a set for O(1) lookups.
Step 1: Check "ad"
Not consistent. Running count: 0
Step 2: Check "bd"
Not consistent. Running count: 0
Step 3: Check "aaab"
Consistent. Running count: 1
Step 4: Check "baa"
Consistent. Running count: 2
Step 5: Check "badab"
Not consistent. Running count: 2
Result
Final count: 2. Out of 5 words, 2 are consistent (every character appears in the allowed set).
For each word, we check every character against the allowed set. The all() function short-circuits on the first disallowed character, so words like "ad" stop checking after seeing "d". Words where every character passes, like "aaab" and "baa", are counted as consistent.
Complexity analysis
| Approach | Time | Space |
|---|---|---|
| Set membership | O(n * m) | O(1) |
Where n is the number of words and m is the average word length.
Time: Building the allowed set takes O(k) where k is the length of allowed, but k is at most 26 (lowercase English letters), so it is O(1). For each of the n words, we check up to m characters, each in O(1) time against the set. Total: O(n * m).
Space: The allowed set contains at most 26 characters, so it uses O(1) space regardless of input size. We do not allocate any data structures that grow with the input.
The building blocks
1. Set construction from a string
Converting a string into a set is one of the most useful one-liners in Python. It gives you O(1) membership testing for any character. You will use this pattern in anagram problems, substring problems, and anywhere you need to quickly check whether a character belongs to a group.
allowed_set = set(allowed)
2. all() with a generator expression
Python's all() function returns True if every element in the iterable is truthy. Paired with a generator expression, it gives you a concise way to check a condition across all elements. The generator is lazy and short-circuits on the first False, making it efficient for early rejection.
all(ch in allowed_set for ch in word)
Edge cases
- Every word is consistent: if
allowedcontains all 26 letters, every possible word is consistent. The function returns the length ofwords. - No words are consistent: if
allowedis a single letter like "a" and no word consists solely of "a", the count is 0. - Empty words array:
sum()over an empty iterable returns 0, which is correct. - Single-character words: each word is just one character check. The logic handles this naturally.
- allowed has all characters in a word repeated: since
allowedcontains distinct characters and we build a set, duplicates inallowedwould not matter anyway, but the problem guarantees distinct characters.
From understanding to recall
You have seen how converting a string to a set and using all() with a generator solves this problem cleanly. The logic is simple. But reproducing it under pressure requires the details to be automatic: remembering to build the set first, using all() instead of a manual loop, and knowing that sum() can count boolean True values.
Spaced repetition locks in these micro-patterns. You practice writing the set construction and the all() check from scratch at increasing intervals. After a few rounds, the code flows out without hesitation. You do not need to think about whether all() short-circuits or whether sum() counts booleans. You just write it.
Related posts
- Valid Anagram - Another character set operation problem where you compare frequency counts across two strings
- Ransom Note - Character availability checking where you verify one string's characters can be sourced from another
- Isomorphic Strings - Character mapping patterns where you track relationships between characters in two strings
CodeBricks breaks Count the Number of Consistent Strings into its set-construction and membership-checking building blocks, then drills them independently with spaced repetition. You type each piece from scratch until the pattern is automatic. When a set membership problem shows up in your interview, you do not hesitate. You just write it.