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 0.
Below is the implementation of the algorithm:
C++
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
const int mod = 1e9 + 7;
int memo[205][205][12][2];
int dp( int idx, int N, int K, string& S, int cn, int p,
int last)
{
if (idx >= N and cn == 0 and p <= K)
return 1;
if (idx >= N or p > K or cn < 0)
return 0;
if (memo[idx][cn][p][last] != -1)
return memo[idx][cn][p][last];
long long x = 0;
if (S[idx] != '?' ) {
if (last == S[idx] - '(' ) {
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 {
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;
}
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 memo[idx][cn][p][last] = x;
}
int countStrings( int N, string& S, int K)
{
memset (memo, -1, sizeof memo);
return dp(0, N, K, S, 0, 0, 0);
}
int main()
{
int n = 6;
string s = "((??))" ;
int k = 3;
cout << countStrings(n, s, k);
return 0;
}
|
Java
import java.util.Arrays;
public class Solution {
static final int mod = 1000000007 ;
static int [][][][] memo = new int [ 205 ][ 205 ][ 12 ][ 2 ];
static int dp( int idx, int N, int K, String S, int cn, int p, int last) {
if (idx >= N && cn == 0 && p <= K)
return 1 ;
if (idx >= N || p > K || cn < 0 )
return 0 ;
if (memo[idx][cn][p][last] != - 1 )
return memo[idx][cn][p][last];
long x = 0 ;
if (S.charAt(idx) != '?' ) {
if (last == S.charAt(idx) - '(' ) {
if (S.charAt(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.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);
}
}
else {
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 memo[idx][cn][p][last] = ( int ) x;
}
static int countStrings( int N, String S, int K) {
for ( int [][][] arr1 : memo) {
for ( int [][] arr2 : arr1) {
for ( int [] arr3 : arr2) {
Arrays.fill(arr3, - 1 );
}
}
}
return dp( 0 , N, K, S, 0 , 0 , 0 );
}
public static void main(String[] args) {
int n = 6 ;
String s = "((??))" ;
int k = 3 ;
System.out.println(countStrings(n, s, k));
}
}
|
Python3
mod = 10 * * 9 + 7
memo = [[[[ - 1 for _ in range ( 12 )] for _ in range ( 205 )] for _ in range ( 205 )] for _ in range ( 2 )]
def dp(idx, N, K, S, cn, p, last):
if idx > = N and cn = = 0 and p < = K:
return 1
if idx > = N or p > K or cn < 0 :
return 0
if memo[last][p][cn][idx] ! = - 1 :
return memo[last][p][cn][idx]
x = 0
if S[idx] ! = '?' :
if last = = ord (S[idx]) - ord ( '(' ):
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 :
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
memo[last][p][cn][idx] = x
return x
def countStrings(N, S, K):
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
return dp( 0 , N, K, S, 0 , 0 , 0 )
if __name__ = = "__main__" :
n = 6
s = "((??))"
k = 3
print (countStrings(n, s, k))
|
C#
using System;
public class Solution
{
static readonly int mod = 1000000007;
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;
}
}
}
}
}
static int dp( int idx, int N, int K, string S, int cn, int p, int last)
{
if (idx >= N && cn == 0 && p <= K)
return 1;
if (idx >= N || p > K || cn < 0)
return 0;
if (memo[idx][cn][p][last] != -1)
return memo[idx][cn][p][last];
long x = 0;
if (S[idx] != '?' )
{
if (last == S[idx] - '(' )
{
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
{
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 memo[idx][cn][p][last] = ( int )x;
}
static int CountStrings( int N, string S, int K)
{
return dp(0, N, K, S, 0, 0, 0);
}
public static void Main( string [] args)
{
int n = 6;
string s = "((??))" ;
int k = 3;
Console.WriteLine(CountStrings(n, s, k));
}
}
|
Javascript
const mod = 10**9 + 7;
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 dp(idx, N, K, S, cn, p, last) {
if (idx >= N && cn === 0 && p <= K) {
return 1;
}
if (idx >= N || p > K || cn < 0) {
return 0;
}
if (memo[last][p][cn][idx] !== -1) {
return memo[last][p][cn][idx];
}
let x = 0;
if (S[idx] !== '?' ) {
if (last === S.charCodeAt(idx) - '(' .charCodeAt()) {
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 {
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;
memo[last][p][cn][idx] = x;
return x;
}
function countStrings(N, S, K) {
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;
}
}
}
}
return dp(0, N, K, S, 0, 0, 0);
}
const n = 6;
const s = "((??))" ;
const k = 3;
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)
|