Given an integer K, a string S of length N, consisting of ‘(‘ or ‘)’ or ‘?’ characters. We can replace each ‘?’ character with either ‘(‘ or ‘)’ character. The task is to find the total number of unique valid strings you can generate such that the maximum length of the substring containing the same characters is no more than K.
A valid string is a string in which every opening braces have its corresponding closing braces and vice versa. For example, strings “(())()”, “”, “(())” are valid but “)(“, “())”, “(())(” are not.
Examples:
Input: N = 6, S = “((??))”, K = 3
Output: 2
Explanation: By replacing the ‘?’ characters we can make 2 valid strings: “((()))” and “(()())”.Input: N = 3, S = “(?)”, K = 1
Output: 0
Explanation: Since the length of the string is odd, no valid string can be generated.
Approach: To solve the problem, follow the below idea:
The problem can be solved using dynamic programming. The recursive function explores the possibilities of replacing ‘?’ with ‘(‘ or ‘)’ while maintaining a balanced bracket sequence and limiting consecutive same brackets to at most k. Memoization is employed for efficiency, and the final count is obtained through dp(0, N, K, S, 0, 0, 0).
Step-by-step algorithm:
- Initialize a 4D dp[][][][] representing index, closing-opening brackets count, unique character and (open or close bracket) respectively.
-
Start iterating in S:
-
If character not equals to ‘?‘:
- Check for unique characters constraints:
- If the last character is open bracket, Increase the count by 1, making the unique character increase by 1.
- Else, decrease the count by 1, making the unique character now 1.
-
Else, check for last character:
- If open, same try replacing it with open and close bracket making the arguments change dp(idx + 1, N, K, S, cn + 1, p + 1, last)
- If close, same replacing open and close bracket making the arguments change dp(idx + 1, N, K, S, cn – 1, 1, 1 – last)
-
If (idx >= N and cn == 0 and p <= K):
- return 1
- return 0.
-
If character not equals to ‘?‘:
Below is the implementation of the algorithm:
// C++ Implementation #include <bits/stdc++.h> #include <iostream> using namespace std;
// Create a dp const int mod = 1e9 + 7;
// Intializing a dp with max value int memo[205][205][12][2];
// Function to iterate in dp for string int dp( int idx, int N, int K, string& S, int cn, int p,
int last)
{ // if index is reached
if (idx >= N and cn == 0 and p <= K)
return 1;
if (idx >= N or p > K or cn < 0)
return 0;
// If the value for this already calculated
if (memo[idx][cn][p][last] != -1)
return memo[idx][cn][p][last];
long long x = 0;
// If character is not equal to '?'
if (S[idx] != '?' ) {
// Get the index difference
if (last == S[idx] - '(' ) {
// If character equal to '('
if (S[idx] == '(' )
x += dp(idx + 1, N, K, S, cn + 1, p + 1,
last);
// Otherwise
else
x += dp(idx + 1, N, K, S, cn - 1, p + 1,
last);
}
else {
if (S[idx] == '(' )
x += dp(idx + 1, N, K, S, cn + 1, 1,
1 - last);
else
x += dp(idx + 1, N, K, S, cn - 1, 1,
1 - last);
}
}
// If charcater not equal to '?"
else {
// Side by side calculate the mod ans
if (last == 0) {
x += dp(idx + 1, N, K, S, cn + 1, p + 1, last);
x %= mod;
x += dp(idx + 1, N, K, S, cn - 1, 1, 1 - last);
x %= mod;
}
// Otherwise
else {
x += dp(idx + 1, N, K, S, cn - 1, p + 1, last);
x %= mod;
x += dp(idx + 1, N, K, S, cn + 1, 1, 1 - last);
x %= mod;
}
}
x %= mod;
// Return the value
return memo[idx][cn][p][last] = x;
} // Function to count string in paranthesis int countStrings( int N, string& S, int K)
{ // Filled the dp array with -1
memset (memo, -1, sizeof memo);
// Call the dp function
return dp(0, N, K, S, 0, 0, 0);
} // Driver code int main()
{ int n = 6;
string s = "((??))" ;
int k = 3;
// Function call
cout << countStrings(n, s, k);
return 0;
} |
import java.util.Arrays;
public class Solution {
// Create a dp
static final int mod = 1000000007 ;
// Initializing a dp with max value
static int [][][][] memo = new int [ 205 ][ 205 ][ 12 ][ 2 ];
// Function to iterate in dp for string
static int dp( int idx, int N, int K, String S, int cn, int p, int last) {
// if index is reached
if (idx >= N && cn == 0 && p <= K)
return 1 ;
if (idx >= N || p > K || cn < 0 )
return 0 ;
// If the value for this already calculated
if (memo[idx][cn][p][last] != - 1 )
return memo[idx][cn][p][last];
long x = 0 ;
// If character is not equal to '?'
if (S.charAt(idx) != '?' ) {
// Get the index difference
if (last == S.charAt(idx) - '(' ) {
// If character equal to '('
if (S.charAt(idx) == '(' )
x += dp(idx + 1 , N, K, S, cn + 1 , p + 1 , last);
// Otherwise
else
x += dp(idx + 1 , N, K, S, cn - 1 , p + 1 , last);
} else {
if (S.charAt(idx) == '(' )
x += dp(idx + 1 , N, K, S, cn + 1 , 1 , 1 - last);
else
x += dp(idx + 1 , N, K, S, cn - 1 , 1 , 1 - last);
}
}
// If character not equal to '?'
else {
// Side by side calculate the mod ans
if (last == 0 ) {
x += dp(idx + 1 , N, K, S, cn + 1 , p + 1 , last) % mod;
x += dp(idx + 1 , N, K, S, cn - 1 , 1 , 1 - last) % mod;
} else {
x += dp(idx + 1 , N, K, S, cn - 1 , p + 1 , last) % mod;
x += dp(idx + 1 , N, K, S, cn + 1 , 1 , 1 - last) % mod;
}
}
x %= mod;
// Return the value
return memo[idx][cn][p][last] = ( int ) x;
}
// Function to count string in parentheses
static int countStrings( int N, String S, int K) {
// Filled the dp array with -1
for ( int [][][] arr1 : memo) {
for ( int [][] arr2 : arr1) {
for ( int [] arr3 : arr2) {
Arrays.fill(arr3, - 1 );
}
}
}
// Call the dp function
return dp( 0 , N, K, S, 0 , 0 , 0 );
}
// Driver code
public static void main(String[] args) {
int n = 6 ;
String s = "((??))" ;
int k = 3 ;
// Function call
System.out.println(countStrings(n, s, k));
}
} // This code is contributed by shivamgupta0987654321 |
# Python3 Implementation # Create a dp mod = 10 * * 9 + 7
# Intializing a dp with max value memo = [[[[ - 1 for _ in range ( 12 )] for _ in range ( 205 )] for _ in range ( 205 )] for _ in range ( 2 )]
# Function to iterate in dp for string def dp(idx, N, K, S, cn, p, last):
# if index is reached
if idx > = N and cn = = 0 and p < = K:
return 1
if idx > = N or p > K or cn < 0 :
return 0
# If the value for this already calculated
if memo[last][p][cn][idx] ! = - 1 :
return memo[last][p][cn][idx]
x = 0
# If character is not equal to '?'
if S[idx] ! = '?' :
# Get the index difference
if last = = ord (S[idx]) - ord ( '(' ):
# If character equal to '('
if S[idx] = = '(' :
x + = dp(idx + 1 , N, K, S, cn + 1 , p + 1 , last)
# Otherwise
else :
x + = dp(idx + 1 , N, K, S, cn - 1 , p + 1 , last)
else :
if S[idx] = = '(' :
x + = dp(idx + 1 , N, K, S, cn + 1 , 1 , 1 - last)
else :
x + = dp(idx + 1 , N, K, S, cn - 1 , 1 , 1 - last)
# If charcater not equal to '?"
else :
# Side by side calculate the mod ans
if last = = 0 :
x + = dp(idx + 1 , N, K, S, cn + 1 , p + 1 , last) % mod
x + = dp(idx + 1 , N, K, S, cn - 1 , 1 , 1 - last) % mod
# Otherwise
else :
x + = dp(idx + 1 , N, K, S, cn - 1 , p + 1 , last) % mod
x + = dp(idx + 1 , N, K, S, cn + 1 , 1 , 1 - last) % mod
x % = mod
# Return the value
memo[last][p][cn][idx] = x
return x
# Function to count string in paranthesis def countStrings(N, S, K):
# Filled the dp array with -1
for i in range ( 2 ):
for j in range (K + 1 ):
for k in range (N + 1 ):
for l in range (N + 1 ):
memo[i][j][k][l] = - 1
# Call the dp function
return dp( 0 , N, K, S, 0 , 0 , 0 )
# Driver code if __name__ = = "__main__" :
n = 6
s = "((??))"
k = 3
# Function call
print (countStrings(n, s, k))
|
using System;
public class Solution
{ // Create a dp
static readonly int mod = 1000000007;
// Initializing a dp with max value
static int [][][][] memo = new int [205][][][];
static Solution()
{
for ( int i = 0; i < memo.Length; i++)
{
memo[i] = new int [205][][];
for ( int j = 0; j < memo[i].Length; j++)
{
memo[i][j] = new int [12][];
for ( int k = 0; k < memo[i][j].Length; k++)
{
memo[i][j][k] = new int [2];
for ( int l = 0; l < 2; l++)
{
memo[i][j][k][l] = -1;
}
}
}
}
}
// Function to iterate in dp for string
static int dp( int idx, int N, int K, string S, int cn, int p, int last)
{
// if index is reached
if (idx >= N && cn == 0 && p <= K)
return 1;
if (idx >= N || p > K || cn < 0)
return 0;
// If the value for this already calculated
if (memo[idx][cn][p][last] != -1)
return memo[idx][cn][p][last];
long x = 0;
// If character is not equal to '?'
if (S[idx] != '?' )
{
// Get the index difference
if (last == S[idx] - '(' )
{
// If character equal to '('
if (S[idx] == '(' )
x += dp(idx + 1, N, K, S, cn + 1, p + 1, last);
// Otherwise
else
x += dp(idx + 1, N, K, S, cn - 1, p + 1, last);
}
else
{
if (S[idx] == '(' )
x += dp(idx + 1, N, K, S, cn + 1, 1, 1 - last);
else
x += dp(idx + 1, N, K, S, cn - 1, 1, 1 - last);
}
}
// If character not equal to '?'
else
{
// Side by side calculate the mod ans
if (last == 0)
{
x += dp(idx + 1, N, K, S, cn + 1, p + 1, last) % mod;
x += dp(idx + 1, N, K, S, cn - 1, 1, 1 - last) % mod;
}
else
{
x += dp(idx + 1, N, K, S, cn - 1, p + 1, last) % mod;
x += dp(idx + 1, N, K, S, cn + 1, 1, 1 - last) % mod;
}
}
x %= mod;
// Return the value
return memo[idx][cn][p][last] = ( int )x;
}
// Function to count string in parentheses
static int CountStrings( int N, string S, int K)
{
// Call the dp function
return dp(0, N, K, S, 0, 0, 0);
}
// Driver code
public static void Main( string [] args)
{
int n = 6;
string s = "((??))" ;
int k = 3;
// Function call
Console.WriteLine(CountStrings(n, s, k));
}
} |
// Create a constant for mod const mod = 10**9 + 7; // Initializing a memoization array with max value const memo = new Array(2).fill( null ).map(() =>
new Array(12).fill( null ).map(() =>
new Array(205).fill( null ).map(() =>
new Array(205).fill(-1)
)
)
); // Function to iterate in dp for string function dp(idx, N, K, S, cn, p, last) {
// if index is reached
if (idx >= N && cn === 0 && p <= K) {
return 1;
}
if (idx >= N || p > K || cn < 0) {
return 0;
}
// If the value for this already calculated
if (memo[last][p][cn][idx] !== -1) {
return memo[last][p][cn][idx];
}
let x = 0;
// If character is not equal to '?'
if (S[idx] !== '?' ) {
// Get the index difference
if (last === S.charCodeAt(idx) - '(' .charCodeAt()) {
// If character equal to '('
if (S[idx] === '(' ) {
x += dp(idx + 1, N, K, S, cn + 1, p + 1, last);
} else {
x += dp(idx + 1, N, K, S, cn - 1, p + 1, last);
}
} else {
if (S[idx] === '(' ) {
x += dp(idx + 1, N, K, S, cn + 1, 1, 1 - last);
} else {
x += dp(idx + 1, N, K, S, cn - 1, 1, 1 - last);
}
}
} else {
// Side by side calculate the mod ans
if (last === 0) {
x += dp(idx + 1, N, K, S, cn + 1, p + 1, last) % mod;
x += dp(idx + 1, N, K, S, cn - 1, 1, 1 - last) % mod;
} else {
x += dp(idx + 1, N, K, S, cn - 1, p + 1, last) % mod;
x += dp(idx + 1, N, K, S, cn + 1, 1, 1 - last) % mod;
}
}
x %= mod;
// Return the value
memo[last][p][cn][idx] = x;
return x;
} // Function to count string in paranthesis function countStrings(N, S, K) {
// Filled the memoization array with -1
for (let i = 0; i < 2; i++) {
for (let j = 0; j < K + 1; j++) {
for (let k = 0; k < N + 1; k++) {
for (let l = 0; l < N + 1; l++) {
memo[i][j][k][l] = -1;
}
}
}
}
// Call the dp function
return dp(0, N, K, S, 0, 0, 0);
} // Driver code const n = 6; const s = "((??))" ;
const k = 3; // Function call console.log(countStrings(n, s, k)); |
Output:
2
Time Complexity: O(N * K * K), where N is the length of input string S and K is the maximum number of consecutive same characters allowed.
Auxiliary Space: O(N * K * K)