Counting Words With a Given Prefix
EasyPrompt
You are given an array of strings words and a string pref.
Return the number of strings in words that contain pref as a prefix.
A prefix of a string s is any leading contiguous substring of s.
Example 1:
pref Example 2:
pref
Constraints:
1 <= words.length <= 1001 <= words[i].length, pref.length <= 100words[i]andprefconsist of lowercase English letters.
Approaches
3 approaches with complexity analysis and trade-offs.
This approach involves building a Trie (also known as a prefix tree) from all the words in the input array. A Trie is a tree-like data structure that stores strings, where each node represents a character and paths from the root to a node represent prefixes. After building the Trie, we can efficiently search for the given prefix.
Algorithm
- Create a
TrieNodeclass withchildren(an array ofTrieNodes of size 26) and an integercountto track how many words pass through or end at this node. - Initialize a root
TrieNode. - For each
wordin thewordsarray, insert it into the Trie:- Start from the
root. - For each character
cin theword:- Find the corresponding child node. If it doesn't exist, create it.
- Move to the child node.
- Increment the
countof the child node.
- Start from the
- To find the number of words with the given prefix
pref:- Start from the
root. - Traverse the Trie according to the characters in
pref. - If at any point a character does not have a corresponding child node, it means no word has this prefix, so return 0.
- If the traversal is successful, the
countof the final node reached is the answer.
- Start from the
Walkthrough
First, we define a TrieNode class. Each node will contain an array of children (one for each letter of the alphabet) and a counter, count, to track how many words pass through this node.
We then build the Trie. We iterate through each word in the words array. For each word, we traverse the Trie from the root, creating new nodes as necessary. At each node along the path for the word, we increment its count.
After the Trie is built, we search for the prefix pref. We traverse the Trie according to the characters in pref.
If we can successfully traverse the entire prefix, the count at the final node gives us the number of words that start with pref.
If at any point during the traversal we find that a path for a character does not exist, it means no word has this prefix, so we can immediately return 0.
This approach is highly efficient if you need to perform many prefix searches on the same set of words, as the expensive part (building the Trie) is done only once. However, for a single search as required by this problem, the overhead of building the Trie makes it less efficient than a simple linear scan.
class TrieNode { TrieNode[] children; int count; public TrieNode() { children = new TrieNode[26]; count = 0; }} class Solution { public int prefixCount(String[] words, String pref) { TrieNode root = new TrieNode(); // Build the Trie for (String word : words) { TrieNode curr = root; for (char c : word.toCharArray()) { int index = c - 'a'; if (curr.children[index] == null) { curr.children[index] = new TrieNode(); } curr = curr.children[index]; curr.count++; } } // Search for the prefix TrieNode curr = root; for (char c : pref.toCharArray()) { int index = c - 'a'; if (curr.children[index] == null) { return 0; // Prefix not found } curr = curr.children[index]; } return curr.count; }}Complexity
Time
O(S + M), where S is the total number of characters in all words and M is the length of the prefix. It takes O(S) time to build the Trie and O(M) time to search for the prefix.
Space
O(S), where S is the total number of characters in all words in the array. In the worst case, where no words share prefixes, the space required is proportional to the sum of the lengths of all words.
Trade-offs
Pros
Extremely fast for multiple queries on the same dataset after the initial build.
Cons
High initial setup cost (time and space) for building the Trie, making it inefficient for a single query.
More complex to implement compared to a simple loop.
This approach iterates through each word in the input array and manually checks if it starts with the given prefix. This avoids using built-in string methods and implements the logic from scratch by comparing characters one by one.
Algorithm
- Initialize
count = 0. - Get the length of the prefix,
prefLen. - For each
wordin thewordsarray:- First, check if
word.length()is less thanprefLen. If it is, continue to the next word. - If the word is long enough, assume it's a match by setting a flag
isPrefix = true. - Loop from
i = 0toprefLen - 1:- Compare
word.charAt(i)withpref.charAt(i). - If the characters do not match, set
isPrefix = falseand break the inner loop.
- Compare
- After the inner loop, if
isPrefixis stilltrue, incrementcount.
- First, check if
- Return
count.
Walkthrough
We initialize a counter variable count to zero. We loop through every word in the words array.
For each word, we first check if its length is less than the prefix's length. If it is, the word cannot possibly have pref as a prefix, so we skip to the next word.
If the word is long enough, we proceed to compare it with the prefix character by character. We can use an inner loop for this. We iterate from the first character up to the length of the prefix. In each iteration, we compare the character from the word with the corresponding character from pref.
If we find any mismatch, we know it's not a prefix, and we can stop checking this word and move to the next one.
If the inner loop completes without finding any mismatches, it means the word starts with the prefix. We then increment our count.
After checking all the words, the final count is our answer.
class Solution { public int prefixCount(String[] words, String pref) { int count = 0; int prefLen = pref.length(); for (String word : words) { if (word.length() >= prefLen) { boolean match = true; for (int i = 0; i < prefLen; i++) { if (word.charAt(i) != pref.charAt(i)) { match = false; break; } } if (match) { count++; } } } return count; }}Complexity
Time
O(N * M), where N is the number of words and M is the length of the prefix. We iterate through N words, and for each word, we perform up to M character comparisons.
Space
O(1), as we only use a few variables to store the count and loop indices.
Trade-offs
Pros
Simple to understand and implement without relying on library functions.
Efficient in terms of space.
Cons
More verbose than using a built-in method.
Re-implements functionality that is already available and likely optimized in the standard library.
This is the most straightforward and idiomatic approach. It involves iterating through the array of words and using the built-in startsWith() method provided by the String class in Java to check for the prefix.
Algorithm
- Initialize a counter
countto 0. - For each
wordin thewordsarray:- Use the built-in
startsWith()method to check ifword.startsWith(pref)is true. - If it is true, increment
count.
- Use the built-in
- After iterating through all the words, return
count.
Walkthrough
The algorithm is very simple. We initialize a counter count to 0.
We then iterate through each word in the words array.
For each word, we call word.startsWith(pref). This method returns true if the word begins with the specified pref string, and false otherwise.
If the method returns true, we increment our count.
After the loop has finished checking all the words, the value of count is the total number of words that have pref as a prefix, which we then return.
This approach is not only concise and easy to read but also leverages the optimized implementation of the standard library. For a single query, this is the most efficient solution.
class Solution { public int prefixCount(String[] words, String pref) { int count = 0; for (String word : words) { if (word.startsWith(pref)) { count++; } } return count; }}Complexity
Time
O(N * M), where N is the number of words and M is the length of the prefix. The `startsWith` method takes O(M) time, and we call it for N words.
Space
O(1), as we only use a single integer for the counter.
Trade-offs
Pros
Most concise, readable, and idiomatic solution.
Leverages optimized standard library functions.
Optimal time and space complexity for a single prefix search.
Cons
For this specific problem context, there are no significant disadvantages.
Solutions
Solution
class Solution {public int prefixCount(String[] words, String pref) { int ans = 0; for (String w : words) { if (w.startsWith(pref)) { ++ans; } } return ans; }}class Solution: def prefixCount( self, words: List[str], pref: str) -> int: return sum(w . startswith(pref) for w in words)class Solution {public: int prefixCount(vector<string> &words, string pref) { int ans = 0; for (auto &w : words) ans += w.find(pref) == 0; return ans; }};Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.