Facebook Pixel

1967. Number of Strings That Appear as Substrings in Word

Problem Description

You are given an array of strings called patterns and a single string called word. Your task is to count how many strings from the patterns array appear as substrings within word.

A substring is defined as a contiguous sequence of characters that appears within another string. For example, "cat" is a substring of "concatenate" because the characters 'c', 'a', 't' appear consecutively in that order.

The solution iterates through each pattern p in the patterns array and checks if it exists as a substring in word using Python's in operator. The expression p in word returns True if p is found as a substring in word, and False otherwise. The sum() function counts the total number of True values (since True equals 1 and False equals 0 in Python), giving us the final count of patterns that are substrings of word.

For example, if patterns = ["a", "abc", "bc", "d"] and word = "abc", the result would be 3 because "a", "abc", and "bc" all appear as substrings in "abc", while "d" does not.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to find which patterns appear as substrings in a given word. The most straightforward approach is to check each pattern individually against the word.

Since we need to determine if one string is contained within another, we can leverage Python's built-in substring checking capability using the in operator. This operator efficiently checks if a pattern exists anywhere within the word as a contiguous sequence.

The key insight is that we don't need to track positions or implement complex string matching algorithms. We simply need a yes/no answer for each pattern: "Does this pattern exist in the word?" Each positive match contributes 1 to our count.

By using a generator expression (p in word for p in patterns), we create a sequence of boolean values - True for patterns that exist in the word and False for those that don't. Since Python treats True as 1 and False as 0 in numeric contexts, we can directly sum these boolean values to get our final count. This eliminates the need for explicit counting logic or conditional statements.

This approach is both concise and efficient for the problem's requirements, as it leverages Python's optimized string searching implementation while maintaining clear, readable code.

Solution Approach

The implementation uses a simulation approach where we traverse through each string in the patterns array and check if it exists as a substring in word.

The algorithm follows these steps:

  1. Iterate through patterns: We go through each string p in the patterns array one by one.

  2. Check substring existence: For each pattern p, we check if it appears as a substring in word using Python's in operator. This operator performs an efficient substring search that returns True if p is found anywhere within word, and False otherwise.

  3. Count matches: We use Python's sum() function to count the total number of patterns that exist as substrings. Since the expression p in word evaluates to a boolean value, and Python treats True as 1 and False as 0 in numeric operations, summing these boolean values gives us the exact count we need.

The complete solution is implemented in a single line:

return sum(p in word for p in patterns)

This generator expression (p in word for p in patterns) creates a sequence of boolean values for each pattern. The sum() function then adds up all the True values (counting as 1 each) to produce the final count.

The time complexity is O(n * m) where n is the number of patterns and m is the average length of pattern strings multiplied by the length of word, as each substring check operation takes time proportional to the lengths involved. The space complexity is O(1) as we only maintain a running count without storing additional data structures.

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:

  • patterns = ["ab", "abc", "bc", "d", "c"]
  • word = "abc"

Step-by-step execution:

  1. Check pattern "ab":

    • Is "ab" in "abc"?
    • Yes! "ab" appears at the beginning of "abc"
    • This evaluates to True (counts as 1)
  2. Check pattern "abc":

    • Is "abc" in "abc"?
    • Yes! "abc" matches the entire word
    • This evaluates to True (counts as 1)
  3. Check pattern "bc":

    • Is "bc" in "abc"?
    • Yes! "bc" appears at the end of "abc"
    • This evaluates to True (counts as 1)
  4. Check pattern "d":

    • Is "d" in "abc"?
    • No! The character "d" doesn't appear anywhere in "abc"
    • This evaluates to False (counts as 0)
  5. Check pattern "c":

    • Is "c" in "abc"?
    • Yes! "c" appears as the last character of "abc"
    • This evaluates to True (counts as 1)

Final calculation: The generator expression produces: [True, True, True, False, True]

When we apply sum() to these boolean values:

  • sum([True, True, True, False, True]) = 1 + 1 + 1 + 0 + 1 = 4

Therefore, 4 patterns from the array appear as substrings in the word "abc".

Solution Implementation

1class Solution:
2    def numOfStrings(self, patterns: List[str], word: str) -> int:
3        """
4        Count how many patterns are substrings of the given word.
5      
6        Args:
7            patterns: List of pattern strings to check
8            word: The target string to search within
9          
10        Returns:
11            Number of patterns that exist as substrings in word
12        """
13        # Initialize counter for matching patterns
14        count = 0
15      
16        # Iterate through each pattern in the list
17        for pattern in patterns:
18            # Check if current pattern is a substring of word
19            if pattern in word:
20                count += 1
21      
22        return count
23
1class Solution {
2    /**
3     * Counts the number of pattern strings that are substrings of the given word.
4     * 
5     * @param patterns Array of pattern strings to search for
6     * @param word The word to search within
7     * @return The count of patterns that appear as substrings in word
8     */
9    public int numOfStrings(String[] patterns, String word) {
10        // Initialize counter for matching patterns
11        int matchCount = 0;
12      
13        // Iterate through each pattern in the patterns array
14        for (String pattern : patterns) {
15            // Check if the current pattern is a substring of word
16            if (word.contains(pattern)) {
17                // Increment counter if pattern is found in word
18                matchCount++;
19            }
20        }
21      
22        // Return the total count of matching patterns
23        return matchCount;
24    }
25}
26
1class Solution {
2public:
3    int numOfStrings(vector<string>& patterns, string word) {
4        int count = 0;
5      
6        // Iterate through each pattern in the patterns array
7        for (const auto& pattern : patterns) {
8            // Check if the current pattern is a substring of word
9            // find() returns string::npos if pattern is not found
10            if (word.find(pattern) != string::npos) {
11                count++;
12            }
13        }
14      
15        return count;
16    }
17};
18
1/**
2 * Counts the number of pattern strings that are substrings of the given word
3 * @param patterns - Array of pattern strings to check
4 * @param word - The word to search within for pattern occurrences
5 * @returns The count of patterns that appear as substrings in word
6 */
7function numOfStrings(patterns: string[], word: string): number {
8    // Filter patterns array to keep only those that exist as substrings in word
9    // Then return the length of the filtered array
10    return patterns.filter((pattern: string) => word.includes(pattern)).length;
11}
12

Time and Space Complexity

The time complexity is O(n × m × k), where n is the number of patterns in the list, m is the length of the word, and k is the average length of each pattern. This is because:

  • We iterate through n patterns
  • For each pattern, the in operator performs substring matching which takes O(m × k) time in the worst case (checking each position in word as a potential start for the pattern)

The space complexity is O(1) as we only use a constant amount of extra space for the sum operation. The generator expression (p in word for p in patterns) doesn't create an intermediate list but yields values one at a time.

Note: The reference answer simplifies the time complexity to O(n × m) by treating the pattern lengths as part of n or considering them constant, which is a valid simplification when analyzing the dominant factors.

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

Common Pitfalls

1. Counting Duplicate Occurrences Instead of Unique Patterns

A common misunderstanding is thinking we need to count how many times each pattern appears in the word, rather than just checking if it exists at least once.

Incorrect approach:

def numOfStrings(self, patterns: List[str], word: str) -> int:
    count = 0
    for pattern in patterns:
        # Wrong: This counts occurrences, not just existence
        count += word.count(pattern)
    return count

Why it's wrong: If patterns = ["a"] and word = "aaa", this would return 3 instead of 1. The problem asks for how many patterns are substrings, not how many times they appear.

Correct approach: Use the boolean check pattern in word which only verifies existence.

2. Handling Empty Patterns

Empty strings are valid substrings of any string in Python. If the patterns array contains empty strings, they should be counted.

Potential issue:

def numOfStrings(self, patterns: List[str], word: str) -> int:
    count = 0
    for pattern in patterns:
        # Some might incorrectly filter out empty patterns
        if pattern and pattern in word:  # Wrong filtering!
            count += 1
    return count

Why it matters: If patterns = ["", "a"] and word = "abc", the result should be 2 (both "" and "a" are substrings), not 1.

Solution: Don't add unnecessary filters. Python's in operator correctly handles empty strings:

"" in "any_string"  # Returns True

3. Case Sensitivity Assumptions

The problem doesn't specify case-insensitive matching, so patterns should match exactly as they appear.

Incorrect assumption:

def numOfStrings(self, patterns: List[str], word: str) -> int:
    word_lower = word.lower()
    return sum(p.lower() in word_lower for p in patterns)

Why it's wrong: If patterns = ["A", "a"] and word = "abc", only "a" should match, giving a count of 1, not 2.

Solution: Stick to exact matching without case conversion unless explicitly required.

4. Counting Duplicate Patterns Multiple Times

If the patterns array contains duplicates, each occurrence should be checked independently.

Example scenario:

  • patterns = ["a", "a", "b"] and word = "abc"
  • Result should be 3 (both "a"s count separately plus "b")

Incorrect approach:

def numOfStrings(self, patterns: List[str], word: str) -> int:
    # Wrong: Using set removes duplicates
    unique_patterns = set(patterns)
    return sum(p in word for p in unique_patterns)

Correct approach: Process each pattern in the original list without deduplication.

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

How many times is a tree node visited in a depth first search?


Recommended Readings

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

Load More