Open In App

Count Valid Substring of paranthesis with at max K consecutive same characters

Last Updated : 29 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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.

Below is the implementation of the algorithm:

C++




// 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;
}


Java




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




# 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))


C#




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));
    }
}


Javascript




// 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)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads