#1397

Find All Good Strings

Hard
StringDynamic ProgrammingString MatchingDynamic ProgrammingBacktrackingString Matching
LeetCode ↗

Approaches

Brute ForceOptimal
Complexity Comparison
Brute ForceOptimal Solution
Time
O(n²)
O(n * m * 2 * 2)
Space
O(1)
O(n * m * 2 * 2)
💡

Intuition

Time O(n * m * 2 * 2)Space O(n * m * 2 * 2)

We can use dynamic programming to efficiently count the valid strings by keeping track of the current position, the position in the evil string, and whether we are still bound by s1 and s2.

⚙️

Algorithm

3 steps
  1. 1Step 1: Use a DP table where dp[pos][posEvil][equalToS1][equalToS2] stores the count of valid strings of length 'pos'.
  2. 2Step 2: Initialize the DP table and iterate through each character position.
  3. 3Step 3: For each character, decide whether to match s1 or s2 or to use any character from 'a' to 'z'. Update the position in the evil string based on the current character.
solution.py24 lines
1def countGoodStrings(n, s1, s2, evil):
2    MOD = 10**9 + 7
3    m = len(evil)
4    dp = [[[-1 for _ in range(2)] for _ in range(2)] for _ in range(n + 1)]
5    def dfs(pos, posEvil, equalToS1, equalToS2):
6        if pos == n:
7            return 1
8        if dp[pos][posEvil][equalToS1][equalToS2] != -1:
9            return dp[pos][posEvil][equalToS1][equalToS2]
10        count = 0
11        limit = s2 if equalToS2 else 'z'
12        for c in range(ord('a'), ord(limit) + 1):
13            nextEqualToS1 = equalToS1 and chr(c) == s1[pos]
14            nextEqualToS2 = equalToS2 and chr(c) == s2[pos]
15            nextPosEvil = posEvil
16            while nextPosEvil > 0 and evil[nextPosEvil] != chr(c):
17                nextPosEvil -= 1
18            if evil[nextPosEvil] == chr(c):
19                nextPosEvil += 1
20            if nextPosEvil < m:
21                count = (count + dfs(pos + 1, nextPosEvil, nextEqualToS1, nextEqualToS2)) % MOD
22        dp[pos][posEvil][equalToS1][equalToS2] = count
23        return count
24    return dfs(0, 0, True, True)

Complexity note: The complexity is derived from the DP table which has dimensions based on the string length, the length of evil, and two boolean states for bounds.

  • 1Dynamic programming is crucial for efficiently solving problems with overlapping subproblems.
  • 2Understanding the constraints and how they affect string generation can lead to optimized solutions.

Solutions and explanations are original Tejav content. Problem titles © LeetCode — use the LeetCode button above for the full problem statement.