Counting Words With a Given Prefix

Easy
#1990Time: 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.1 company
Data structures
Companies

Prompt

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 <= 100
  • 1 <= words[i].length, pref.length <= 100
  • words[i] and pref consist 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 TrieNode class with children (an array of TrieNodes of size 26) and an integer count to track how many words pass through or end at this node.
  • Initialize a root TrieNode.
  • For each word in the words array, insert it into the Trie:
    • Start from the root.
    • For each character c in the word:
      • Find the corresponding child node. If it doesn't exist, create it.
      • Move to the child node.
      • Increment the count of the child node.
  • 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 count of the final node reached is the answer.

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.

Solutions

class Solution {public  int prefixCount(String[] words, String pref) {    int ans = 0;    for (String w : words) {      if (w.startsWith(pref)) {        ++ans;      }    }    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.