Facebook Pixel

2255. Count Prefixes of a Given String

Problem Description

You are given an array of strings words and a string s. All strings contain only lowercase English letters.

Your task is to count how many strings from the words array are prefixes of the string s.

A prefix is a substring that appears at the beginning of a string. For example:

  • "ab" is a prefix of "abc"
  • "abc" is a prefix of "abcdef"
  • "bc" is NOT a prefix of "abcd" (it doesn't start from the beginning)

The solution uses Python's built-in startswith() method to check if s starts with each word w from the array. The expression s.startswith(w) returns True if w is a prefix of s, and False otherwise. By using sum() on these boolean values (where True counts as 1 and False as 0), we get the total count of words that are prefixes of s.

For example, if words = ["a", "abc", "bc", "d"] and s = "abc", the answer would be 2 because:

  • "a" is a prefix of "abc"
  • "abc" is a prefix of "abc"
  • "bc" is NOT a prefix of "abc"
  • "d" is NOT a prefix of "abc"
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to find which strings from an array are prefixes of a given string. The most straightforward approach is to check each word individually against the target string.

When we think about checking if one string is a prefix of another, we need to verify that the target string starts with exactly the same characters as the potential prefix. For instance, if we want to check if "ab" is a prefix of "abc", we need to confirm that the first two characters of "abc" match "ab" exactly.

Python provides a built-in method startswith() that does exactly this check - it returns True if a string begins with the specified prefix, and False otherwise. This eliminates the need to manually compare characters or slice strings.

Since we need to count how many words satisfy this condition, we can leverage Python's ability to treat boolean values as numbers (True as 1, False as 0). By using a generator expression s.startswith(w) for w in words, we create a sequence of boolean values indicating whether each word is a prefix. The sum() function then adds these up, effectively counting the True values.

This approach is both concise and efficient - we make a single pass through the array, perform one prefix check per word, and directly obtain our count. The time complexity is O(n * m) where n is the number of words and m is the average length of the words (for the prefix comparison), which is optimal since we must examine each word at least once.

Solution Approach

The solution implements a traversal counting approach where we iterate through each word in the words array and check if it's a prefix of the string s.

The implementation uses a single line of code that combines iteration and counting:

return sum(s.startswith(w) for w in words)

Let's break down how this works:

  1. Iteration through the array: We use a generator expression for w in words to iterate through each string in the words array.

  2. Prefix checking: For each word w, we call s.startswith(w). This method checks if the string s begins with the substring w. It returns:

    • True if w is a prefix of s
    • False if w is not a prefix of s
  3. Counting mechanism: The sum() function adds up all the boolean values from the generator expression. In Python, True is treated as 1 and False as 0 when used in arithmetic operations. Therefore, sum() effectively counts the number of True values, which represents the number of words that are prefixes of s.

For example, if we have:

  • words = ["a", "ab", "bc"]
  • s = "abc"

The execution would be:

  • s.startswith("a")True (1)
  • s.startswith("ab")True (1)
  • s.startswith("bc")False (0)
  • sum([True, True, False])sum([1, 1, 0]) → 2

The algorithm makes a single pass through the array with no additional data structures needed, making it both space-efficient (O(1) extra space) and straightforward to implement.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to illustrate how the solution works.

Given:

  • words = ["ab", "a", "abc", "bc", "d"]
  • s = "abcd"

Goal: Count how many strings from words are prefixes of "abcd".

Step-by-step execution:

  1. Check "ab":

    • Does "abcd" start with "ab"?
    • Compare: "ab" matches the first 2 characters of "abcd"
    • s.startswith("ab")True (counts as 1)
  2. Check "a":

    • Does "abcd" start with "a"?
    • Compare: "a" matches the first character of "abcd"
    • s.startswith("a")True (counts as 1)
  3. Check "abc":

    • Does "abcd" start with "abc"?
    • Compare: "abc" matches the first 3 characters of "abcd"
    • s.startswith("abc")True (counts as 1)
  4. Check "bc":

    • Does "abcd" start with "bc"?
    • Compare: "abcd" starts with "a", not "b"
    • s.startswith("bc")False (counts as 0)
  5. Check "d":

    • Does "abcd" start with "d"?
    • Compare: "abcd" starts with "a", not "d"
    • s.startswith("d")False (counts as 0)

Final calculation:

  • The generator expression produces: [True, True, True, False, False]
  • When passed to sum(): [1, 1, 1, 0, 0]
  • Result: 1 + 1 + 1 + 0 + 0 = 3

Therefore, 3 strings from the array ("ab", "a", and "abc") are prefixes of "abcd".

Solution Implementation

1class Solution:
2    def countPrefixes(self, words: List[str], s: str) -> int:
3        """
4        Count the number of strings in words that are prefixes of string s.
5      
6        Args:
7            words: List of strings to check as potential prefixes
8            s: Target string to check prefixes against
9          
10        Returns:
11            Integer count of how many words are prefixes of s
12        """
13        # Initialize counter for prefix matches
14        count = 0
15      
16        # Iterate through each word in the list
17        for word in words:
18            # Check if current word is a prefix of string s
19            if s.startswith(word):
20                count += 1
21      
22        return count
23```
24
25Alternative implementation using the original concise approach with comments:
26
27```python3
28class Solution:
29    def countPrefixes(self, words: List[str], s: str) -> int:
30        """
31        Count the number of strings in words that are prefixes of string s.
32      
33        Args:
34            words: List of strings to check as potential prefixes
35            s: Target string to check prefixes against
36          
37        Returns:
38            Integer count of how many words are prefixes of s
39        """
40        # Use sum with generator expression to count True values
41        # s.startswith(w) returns True if w is a prefix of s, False otherwise
42        # sum() treats True as 1 and False as 0
43        return sum(s.startswith(word) for word in words)
44
1class Solution {
2    /**
3     * Counts the number of strings in the words array that are prefixes of string s.
4     * 
5     * @param words Array of strings to check as potential prefixes
6     * @param s The target string to check prefixes against
7     * @return The count of strings from words array that are prefixes of s
8     */
9    public int countPrefixes(String[] words, String s) {
10        // Initialize counter for valid prefixes
11        int prefixCount = 0;
12      
13        // Iterate through each word in the words array
14        for (String word : words) {
15            // Check if current word is a prefix of string s
16            if (s.startsWith(word)) {
17                // Increment counter if word is a valid prefix
18                prefixCount++;
19            }
20        }
21      
22        // Return the total count of valid prefixes
23        return prefixCount;
24    }
25}
26
1class Solution {
2public:
3    int countPrefixes(vector<string>& words, string s) {
4        int count = 0;
5      
6        // Iterate through each word in the words array
7        for (const auto& word : words) {
8            // Check if the current word is a prefix of string s
9            // starts_with() returns true if s begins with word, false otherwise
10            // The boolean result is implicitly converted to 1 (true) or 0 (false)
11            count += s.starts_with(word);
12        }
13      
14        return count;
15    }
16};
17
1/**
2 * Counts the number of strings in the words array that are prefixes of string s
3 * @param words - Array of strings to check as potential prefixes
4 * @param s - Target string to check prefixes against
5 * @returns Number of strings from words array that are prefixes of s
6 */
7function countPrefixes(words: string[], s: string): number {
8    // Filter the words array to keep only strings that are prefixes of s
9    // Then return the count of filtered elements
10    return words.filter((word: string) => s.startsWith(word)).length;
11}
12

Time and Space Complexity

The time complexity is O(m × n), where m is the number of words in the array and n is the length of string s. This is because:

  • We iterate through all m words in the array
  • For each word, the startswith() method performs a character-by-character comparison which in the worst case compares up to n characters (the length of string s)
  • Therefore, the total time complexity is O(m × n)

The space complexity is O(1) as we only use a constant amount of extra space to store the count result. The generator expression in sum() doesn't create an intermediate list but processes elements one by one, using only constant additional memory.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Empty String Edge Case

One common pitfall is not considering that an empty string "" is technically a prefix of any string. If the words array contains empty strings, they will be counted as valid prefixes.

Problem Example:

words = ["a", "", "abc"]
s = "abcd"
# Result: 3 (all three are prefixes, including "")

Solution: If empty strings should not be counted, add a length check:

return sum(s.startswith(w) and len(w) > 0 for w in words)

2. Case Sensitivity Confusion

While the problem states all strings contain only lowercase letters, in real-world scenarios, developers might forget that startswith() is case-sensitive.

Problem Example:

words = ["A", "ab"]
s = "abc"
# "A" will NOT be counted as a prefix due to case difference

Solution: For case-insensitive matching (if needed):

return sum(s.lower().startswith(w.lower()) for w in words)

3. Performance with Large Datasets

When dealing with very long strings or many words, the repeated string prefix checking can become inefficient. Each startswith() call performs character-by-character comparison.

Problem Example:

# If s has length 10^6 and words has 10^4 elements with average length 1000
# This results in many redundant character comparisons

Solution: For better performance with large datasets, consider using a Trie (prefix tree):

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_end = False

def countPrefixes(words, s):
    # Build trie from words
    root = TrieNode()
    for word in words:
        node = root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
        node.is_end = True
  
    # Count prefixes by traversing s
    count = 0
    node = root
    for char in s:
        if char not in node.children:
            break
        node = node.children[char]
        if node.is_end:
            count += 1
  
    return count

4. Assuming Word is Always Shorter Than s

Developers might assume all words in the array are shorter than s, but startswith() correctly handles cases where the word is longer than s (returns False).

Problem Example:

words = ["abc", "abcdef"]
s = "abc"
# "abcdef" is NOT a prefix of "abc" (correctly returns False)
# Result: 1 (only "abc" is a prefix)

This is handled correctly by the default implementation, but it's important to understand this behavior when debugging or testing edge cases.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What are the most two important steps in writing a depth first search function? (Select 2)


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More