Count Ways To Build Good Strings
Leetcode Daily Challenge (13th May, 2023)
Problem Statement:-
Given the integers zero
, one
, low
, and high
, we can construct a string by starting with an empty string, and then at each step perform either of the following:
Append the character
'0'
zero
times.Append the character
'1'
one
times.
This can be performed any number of times.
A good string is a string constructed by the above process having a length between low
and high
(inclusive).
Return the number of different good strings that can be constructed satisfying these properties. Since the answer can be large, return it modulo 10<sup>9</sup> + 7
.
Link: https://leetcode.com/problems/count-ways-to-build-good-strings/
Problem Explanation with examples:-
Example 1
Input: low = 3, high = 3, zero = 1, one = 1
Output: 8
Explanation:
One possible valid good string is "011".
It can be constructed as follows: "" -> "0" -> "01" -> "011".
All binary strings from "000" to "111" are good strings in this example.
Example 2
Input: low = 2, high = 3, zero = 1, one = 2
Output: 5
Explanation: The good strings are "00", "11", "000", "110", and "011".
Constraints
1 <= low <= high <= 10<sup>5</sup>
1 <= zero, one <= low
Intuition:-
We don't need to form the string, we just need to keep track of the length of the string.
We just need to check if the length of the string is between low and high.
There are two cases for each index, either we take zero zeros or we take one ones.
DP is a suitable choice for this problem as we can store the results of the subproblems and hence we don't need to repeat the calculations.
Finally we return the sum of the results of all the subproblems with modulo 10^9+7.
Solution:-
Take the modulo 10^9+7 in a variable mod.
Define a function solve(i) which returns the number of good strings that can be formed if we start from index I.
If i > high then return 0.
Take a variable res to store the result. Add 1 if i >= low else add 0. Then add solve(i+zero)%mod and solve(i+one)%mod.
Return res%mod.
Code:-
JAVA Solution
class Solution {
Map<Integer, Integer> memo = new HashMap<>();
int MOD = 1000000007;
public int countGoodStrings(int low, int high, int zero, int one) {
return solve(0, low, high, zero, one);
}
private int solve(int i, int low, int high, int zero, int one) {
if (i > high) {
return 0;
}
if (i >= low && memo.containsKey(i)) {
return memo.get(i);
}
int res = ((i >= low ? 1 : 0) + solve(i + zero, low, high, zero, one) + solve(i + one, low, high, zero, one)) % MOD;
if (i >= low) {
memo.put(i, res);
}
return res;
}
}
Python Solution
class Solution:
def countGoodStrings(self, low: int, high: int, zero: int, one: int) -> int:
mod = 10**9+7
@cache
def solve(i):
if i > high:
return 0
res = ((1 if i >= low else 0) + (solve(i+zero)%mod) + (solve(i+one)%mod))%mod
return (res)%mod
return solve(0)
Complexity Analysis:-
TIME:-
The time complexity is O(n) where n is the length of the string. We are using memoization to store the results of the subproblems and hence we are not repeating the calculations. We only visit each index once.
SPACE:-
The space complexity is O(n) where n is the length of the string. We are using memoization to store the results of the subproblems.