Watch 5 video solutions for Find All Good Strings, a hard level problem involving String, Dynamic Programming, String Matching. This walkthrough by Happy Coding has 2,626 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
Given the strings s1 and s2 of size n and the string evil, return the number of good strings.
A good string has size n, it is alphabetically greater than or equal to s1, it is alphabetically smaller than or equal to s2, and it does not contain the string evil as a substring. Since the answer can be a huge number, return this modulo 109 + 7.
Example 1:
Input: n = 2, s1 = "aa", s2 = "da", evil = "b" Output: 51 Explanation: There are 25 good strings starting with 'a': "aa","ac","ad",...,"az". Then there are 25 good strings starting with 'c': "ca","cc","cd",...,"cz" and finally there is one good string starting with 'd': "da".
Example 2:
Input: n = 8, s1 = "leetcode", s2 = "leetgoes", evil = "leet" Output: 0 Explanation: All strings greater than or equal to s1 and smaller than or equal to s2 start with the prefix "leet", therefore, there is not any good string.
Example 3:
Input: n = 2, s1 = "gx", s2 = "gz", evil = "x" Output: 2
Constraints:
s1.length == ns2.length == ns1 <= s21 <= n <= 5001 <= evil.length <= 50Problem Overview: You are given two strings s1 and s2 of length n, and a forbidden substring evil. The task is to count how many strings of length n lie lexicographically between s1 and s2 (inclusive) and do not contain evil as a substring.
Approach 1: Dynamic Programming with Character Level Constraints (O(n * m * 26) time, O(n * m * 4) space)
This approach builds the string character by character while maintaining constraints from s1 and s2. A DP state typically tracks index, how many characters of evil have matched so far, and two flags indicating whether the current prefix is still bounded by s1 or s2. For each position, iterate through possible characters ('a' to 'z') within the allowed bounds and update the match length for evil. If the match length reaches len(evil), that branch is discarded. This method combines dynamic programming with prefix checking to prune invalid strings early.
Approach 2: Dynamic Programming with Automata (O(n * m * 26) time, O(m * 26) automaton space)
The optimal strategy builds a finite automaton for the evil string using prefix transitions. Each state represents how many characters of evil are currently matched. When you append a new character, the automaton immediately tells the next state using precomputed transitions. The DP state becomes (index, matchedLen, lowerBound, upperBound). At every step, iterate over valid characters and transition using the automaton. This avoids recomputing prefix matches repeatedly and keeps the DP transitions fast. It heavily relies on string matching concepts combined with dynamic programming.
Approach 3: String Matching with KMP for Evil Substring (O(m) preprocessing, integrated DP O(n * m * 26))
The Knuth-Morris-Pratt (KMP) algorithm is used to preprocess the evil substring by building the LPS (longest prefix suffix) array. This array determines how the match length changes when characters mismatch while constructing candidate strings. During DP transitions, instead of scanning prefixes manually, you update the matched prefix length using the LPS table. This ensures substring detection happens in constant time per transition while avoiding full substring comparisons.
Recommended for interviews: Interviewers usually expect the DP + KMP automaton approach. It shows you understand how to combine lexicographic constraints, stateful substring matching, and memoized DP. Starting with the character-constrained DP helps demonstrate the core idea. Converting the substring check into a KMP-based automaton is the step that turns a slow solution into the optimal one.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| DP with Character Level Constraints | O(n * m * 26) | O(n * m * 4) | Good starting point to understand lexicographic bounds and DP state transitions. |
| DP with Automata | O(n * m * 26) | O(m * 26) | Optimal approach when substring detection must be fast during DP transitions. |
| KMP-based Evil Substring Matching | O(m) preprocessing + O(n * m * 26) | O(m) | Best when integrating efficient substring matching into DP using prefix function. |