Open In App

Range Queries for Longest Correct Bracket Subsequence Set | 2

Given a bracket sequence or in other words a string S of length n, consisting of characters ‘(‘ and ‘)’. Find the length of the maximum correct bracket subsequence of sequence for a given query range. Note: A correct bracket sequence is the one that has matched bracket pairs or which contains another nested correct bracket sequence. For e.g (), (()), ()() are some correct bracket sequence. 

Examples:

Input : S = ())(())(())(
        Start Index of Range = 0, 
        End Index of Range = 11
Output : 10
Explanation:  Longest Correct Bracket Subsequence is ()(())(())

Input : S = ())(())(())(
        Start Index of Range = 1, 
        End Index of Range = 2
Output : 0

Approach: In the Previous post (SET 1) we discussed a solution that works in O(long) for each query, now is this post we will go to see a solution that works in O(1) for each query. 

The idea is based on the Post length of the longest valid balanced substring If we marked indexes of all Balanced parentheses/brackets in a temporary array (here we named it BCP[], BOP[] ) then we answer each query in O(1) time. 

Algorithm :

stack is used to get the index of balance bracket.
Traverse a string from 0 ..to n
IF we seen a closing bracket,
( i.e., str[i] = ')' && stack is not empty )

Then mark both "open & close" bracket indexes as 1.
BCP[i] = 1;
BOP[stk.top()] = 1;

And At last, stored cumulative sum of BCP[] & BOP[]
Run a loop from 1 to n
BOP[i] +=BOP[i-1], BCP[i] +=BCP[i-1]

Now you can answer each query in O(1) time

(BCP[e] - BOP[s-1]])*2;

Below is the implementation of the above idea.

#include <bits/stdc++.h>
using namespace std;

void constructBalanceArray(int BOP[], int BCP[], const char* str, int n) {
    stack<int> stk;
    fill(BOP, BOP + n + 1, 0);
    fill(BCP, BCP + n + 1, 0);

    for (int i = 0; i < n; i++) {
        if (str[i] == '(') {
            stk.push(i);
        } else { // It's a ')'
            if (!stk.empty()) {
                int openIndex = stk.top();
                stk.pop();
                BOP[openIndex] = 1; // There's a valid '(' at openIndex
                BCP[i] = 1;         // There's a valid ')' at i
            }
        }
    }

    // Convert the BOP and BCP into prefix sums
    for (int i = 1; i <= n; i++) {
        BOP[i] += BOP[i - 1];
        BCP[i] += BCP[i - 1];
    }
}

int query(int BOP[], int BCP[], int s, int e) {
    if (s == 0) {
        return (BCP[e] - BOP[s]) * 2;
    } else {
        return (BCP[e] - BCP[s - 1] - (BOP[s] - BOP[s - 1])) * 2;
    }
}

int main() {
    const char str[] = "())(())(())(";
    int n = strlen(str);

    int BCP[n + 1], BOP[n + 1];

    constructBalanceArray(BOP, BCP, str, n);

    vector<pair<int, int>> queries = {{4, 11}, {3, 4}, {0, 2}, {0, 4}, {1, 2}};
    for (const auto& query_pair : queries) {
        int start = query_pair.first;
        int end = query_pair.second;
        cout << "Maximum Length Correct Bracket Subsequence between " << start + 1 << " and " << end + 1 << " = " << query(BOP, BCP, start, end) << endl;
    }

    return 0;
}
import java.util.*;

class GFG {

    static void constructBalanceArray(int[] BOP, int[] BCP, String str, int n) {
        Stack<Integer> stk = new Stack<>();
        Arrays.fill(BOP, 0);
        Arrays.fill(BCP, 0);

        for (int i = 0; i < n; i++) {
            if (str.charAt(i) == '(') {
                stk.push(i);
            } else { // It's a ')'
                if (!stk.isEmpty()) {
                    int openIndex = stk.pop();
                    BOP[openIndex] = 1; // Mark this '(' as balanced
                    BCP[i] = 1;         // Mark this ')' as balanced
                }
            }
        }

        // Convert to prefix sums
        for (int i = 1; i < n; i++) {
            BOP[i] += BOP[i - 1];
            BCP[i] += BCP[i - 1];
        }
    }

    static int query(int[] BOP, int[] BCP, int s, int e) {
        if (s > 0 && BOP[s - 1] == BOP[s]) {
            return (BCP[e] - BOP[s]) * 2;
        } else {
            return (BCP[e] - (s > 0 ? BOP[s - 1] : 0)) * 2;
        }
    }

    public static void main(String[] args) {
        String str = "())(())(())(";
        int n = str.length();
        int[] BCP = new int[n];
        int[] BOP = new int[n];

        constructBalanceArray(BOP, BCP, str, n);

        // Define the queries
        int[][] queries = {
            {5, 11}, // indices are 0-based, add 1 if 1-based is needed
            {4, 5},
            {1, 5},
            {0, 2}
        };

        for (int[] query : queries) {
            int startIndex = query[0];
            int endIndex = query[1];
            System.out.println("Maximum Length Correct Bracket Subsequence between " +
                               (startIndex + 1) + " and " + (endIndex + 1) +
                               " = " + query(BOP, BCP, startIndex, endIndex));
        }
    }
}
def constructBalanceArray(BOP, BCP, s, n):
    stk = []  # No need to push -1 as mentioned in the comment; we never use that

    for i in range(n):
        if s[i] == '(':
            stk.append(i)
        else:
            if stk:
                open_index = stk.pop()
                BOP[open_index] = 1
                BCP[i] = 1
            # No else needed here; the initial values are zero

    # Convert to prefix sums
    for i in range(1, n):
        BOP[i] += BOP[i - 1]
        BCP[i] += BCP[i - 1]

def query(BOP, BCP, s, e):
    s_adjusted = s - 1  # Adjusting for 0-based index access
    e_adjusted = e

    if s_adjusted > 0 and BOP[s_adjusted - 1] == BOP[s_adjusted]:
        return (BCP[e_adjusted] - BOP[s_adjusted]) * 2
    else:
        return (BCP[e_adjusted] - (BOP[s_adjusted - 1] if s_adjusted > 0 else 0)) * 2

if __name__ == '__main__':
    string = "())(())(())("
    n = len(string)

    BCP = [0] * n
    BOP = [0] * n

    constructBalanceArray(BOP, BCP, string, n)

    queries = [(5, 11), (4, 5), (1, 5)]
    for start, end in queries:
        max_length = query(BOP, BCP, start, end)
        print(f"Maximum Length of Balanced Bracket Subsequence from {start} to {end} = {max_length}")
using System;
using System.Collections.Generic;

class GFG
{
    // Function for precomputation
    static void constructBalanceArray(int[] BOP, int[] BCP, string str, int n)
    {
        Stack<int> stk = new Stack<int>();

        for (int i = 0; i < n; i++)
        {
            if (str[i] == '(')
            {
                stk.Push(i);
            }
            else
            {
                if (stk.Count > 0)
                {
                    int matchedOpenIndex = stk.Pop();
                    BOP[matchedOpenIndex] = 1;
                    BCP[i] = 1;
                }
            }
        }

        // Building prefix sums
        for (int i = 1; i < n; i++)
        {
            BOP[i] += BOP[i - 1];
            BCP[i] += BCP[i - 1];
        }
    }

    // Function to return output of each query in O(1)
    static int query(int[] BOP, int[] BCP, int s, int e)
    {
        if (s > 1 && BOP[s - 2] == BOP[s - 1])
        {
            return (BCP[e] - BOP[s - 1]) * 2;
        }
        else
        {
            return (BCP[e] - (s > 1 ? BOP[s - 2] : 0)) * 2;
        }
    }

    // Driver code
    public static void Main()
    {
        string str = "())(())(())(";
        int n = str.Length;
        int[] BCP = new int[n + 1];
        int[] BOP = new int[n + 1];
        constructBalanceArray(BOP, BCP, str, n);

        // Test cases
        var queries = new[] { (5, 11), (4, 5), (1, 5) };
        foreach (var (startIndex, endIndex) in queries)
        {
            int maxLen = query(BOP, BCP, startIndex, endIndex);
            Console.WriteLine($"Maximum Length Correct Bracket Subsequence between {startIndex} and {endIndex} = {maxLen}");
        }
    }
}
<script>
// Function for precomputation
function constructBalanceArray(BOP, BCP, str, n) {
    var stk = [];
    for (var i = 0; i < n; i++) {
        if (str[i] === '(')
            stk.push(i);
        else {
            if (stk.length !== 0) {
                BCP[i] = 1;
                BOP[stk[stk.length - 1]] = 1;
                stk.pop();
            } else
                BCP[i] = 0;
        }
    }

    for (var i = 1; i < n; i++) {
        BCP[i] += BCP[i - 1];
        BOP[i] += BOP[i - 1];
    }
}

// Function to return output of each query in O(1)
function query(BOP, BCP, s, e) {
    if (BOP[s - 1] === BOP[s]) {
        return (BCP[e] - BOP[s]) * 2;
    } else {
        return (BCP[e] - BOP[s] + 1) * 2;
    }
}

// Driver program to test above function
var str = "())(())(())(";
var n = str.length;
var BCP = Array(n + 1).fill(0);
var BOP = Array(n + 1).fill(0);
constructBalanceArray(BOP, BCP, str, n);

var startIndex = 5, endIndex = 11;
document.write("Maximum Length of Correct Bracket Subsequence between " +
    startIndex + " and " + endIndex + " = " +
    query(BOP, BCP, startIndex, endIndex) + "<br>");

startIndex = 4, endIndex = 5;
document.write("Maximum Length of Correct Bracket Subsequence between " +
    startIndex + " and " + endIndex + " = " +
    query(BOP, BCP, startIndex, endIndex) + "<br>");

startIndex = 1, endIndex = 5;
document.write("Maximum Length of Correct Bracket Subsequence between " +
    startIndex + " and " + endIndex + " = " +
    query(BOP, BCP, startIndex, endIndex) + "<br>");

</script>

Output
Maximum Length Correct Bracket Subsequence between 5 and 11 = 4
Maximum Length Correct Bracket Subsequence between 4 and 5 = 0
Maximum Length Correct Bracket Subsequence between 1 and 5 = 2

The time complexity for each query is O(1).
Overall time Complexity: O(n)
Auxiliary Space: O(n)

Article Tags :