Open In App

Pairs involved in Balanced Parentheses

Last Updated : 26 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a string of brackets, the task is to find the number of pairs of brackets involved in a balanced sequence in a given range.

Examples :  

Input : ((())(()
Range : 1 5
Range : 3 8
Output : 2
         2
Explanation :  In range 1 to 5 ((()), 
there are the two pairs. In range 3 to 8 ())
((), there are the two pairs.

Input : )()()))
Range : 1 2
Range : 4 7
Output : 0
         1
Explanation :  In range 1 to 2 )( there 
is no pair. In range 4 to 7 ())), 
there is the only pair

Prerequisite : Segment Trees 

Approach : 

Here, in segment tree, for each node, keep some simple elements, like integers or sets or vectors or etc. 
For each node keep three integers : 

  • t = Answer for the interval. 
  • o = The number of opening brackets ‘(‘ remaining after deleting the brackets those who belong to the correct bracket sequence in this interval with length t. 
  • c = The number of closing brackets ‘)’ remaining after deleting the brackets those who belong to the correct bracket sequence in this interval with length t. 

Now, having these variables, queries can be answered easily using segment tree.

Below is the implementation of the above approach : 

C++




// CPP code to find the number of pairs
// involved in balanced parentheses
#include <bits/stdc++.h>
using namespace std;
 
// Our struct node
struct node {
     
    // three variables required
    int t, o, c;
};
 
// Declare array of nodes of very big
// size which acts as segment tree here.
struct node tree_arr[5 * 1000];
 
// To build a segment tree we pass 1 as
// 'id' 0 as 'l' and l as 'n'.
// Here, we consider query's interval as [x, y)
void build(int id, int l, int r, string s)
{
    /* this base condition is common to
       build any segment tree*/
    // This is the base
    // Only one element left
    if (r - l < 2) {
         
        // If that element is open bracket
        if (s[l] == '(')
            tree_arr[id].o = 1;
         
        // If that element is open bracket
        else
            tree_arr[id].c = 1;
        return;
    }
 
    // Next three lines are common
    // for any segment tree.
    int mid = (l + r) / 2;
     
    // for left tree
    build(2 * id, l, mid, s);
     
    // for right tree
    build(2 * id + 1, mid, r, s);
 
    // Here we take minimum of left tree
    // opening brackets and right tree
    // closing brackets
    int tmp = min(tree_arr[2 * id].o,
                  tree_arr[2 * id + 1].c);
 
    // we add that to our answer.
    tree_arr[id].t = tree_arr[2 * id].t +
              tree_arr[2 * id + 1].t + tmp;
 
    // Remove the answer from opening brackets
    tree_arr[id].o = tree_arr[2 * id].o +
               tree_arr[2 * id + 1].o - tmp;
 
    // Remove the answer from opening brackets
    tree_arr[id].c = tree_arr[2 * id].c +
               tree_arr[2 * id + 1].c - tmp;
}
 
// This will return the answer for each query.
// Here we consider query's interval as [x, y)
node segment(int x, int y, int id,
             int l, int r, string s)
{
    // If the given interval is out of range
    if (l >= y || x >= r) {
        struct node tem;
        tem.t = 0;
        tem.o = 0;
        tem.c = 0;
        return tem;
    }
 
    // If the given interval completely lies
    if (x <= l && r <= y)
        return tree_arr[id];
 
    // Next three lines are common for
    // any segment tree.
    int mid = (l + r) / 2;
     
    // For left tree
    struct node a =
           segment(x, y, 2 * id, l, mid, s);
     
    // For right tree
    struct node b =
           segment(x, y, 2 * id + 1, mid, r, s);
 
    // Same as made in build function
    int temp;
    temp = min(a.o, b.c);
    struct node vis;
    vis.t = a.t + b.t + temp;
    vis.o = a.o + b.o - temp;
    vis.c = a.c + b.c - temp;
 
    return vis;
}
 
// Driver code
int main()
{
    string s = "((())(()";
    int n = s.size();
 
    // range for query
    int a = 3, b = 8;
     
    build(1, 0, n, s);
     
    // Here we consider query's interval as [a, b)
    // We subtract 1 from 'a' because indexes start
    // from 0.
    struct node p = segment(a-1, b, 1, 0, n, s);
    cout << p.t << endl;
     
    return 0;
}


Java




// Java code for the above approach
import java.util.Scanner;
 
// Our struct node
class Node {
  int t, o, c;
}
 
class SegmentTree {
  Node[] tree_arr;
 
  // Declare array of nodes of very big size which acts as segment tree here.
  SegmentTree(int n) {
    tree_arr = new Node[5 * n];
    for (int i = 0; i < 5 * n; i++) {
      tree_arr[i] = new Node();
    }
  }
 
  // To build a segment tree we pass 1 as 'id' 0 as 'l' and l as 'n'.
  // Here, we consider query's interval as [x, y)
  void build(int id, int l, int r, String s) {
    /* this base condition is common to
           build any segment tree*/
    // This is the base
    // Only one element left
    if (r - l < 2) {
      // If that element is open bracket
      if (s.charAt(l) == '(') {
        tree_arr[id].o = 1;
      } else {
        tree_arr[id].c = 1;
      }
      return;
    }
 
    // Next three lines are common
    // for any segment tree.
    int mid = (l + r) / 2;
 
    // for left tree
    build(2 * id, l, mid, s);
 
    // for right tree
    build(2 * id + 1, mid, r, s);
 
    // Here we take minimum of left tree opening brackets and right tree closing brackets
    int temp = Math.min(tree_arr[2 * id].o, tree_arr[2 * id + 1].c);
 
    // we add that to our answer.
    tree_arr[id].t = tree_arr[2 * id].t + tree_arr[2 * id + 1].t + temp;
 
    // Remove the answer from opening brackets
    tree_arr[id].o = tree_arr[2 * id].o + tree_arr[2 * id + 1].o - temp;
 
    // Remove the answer from opening brackets
    tree_arr[id].c = tree_arr[2 * id].c + tree_arr[2 * id + 1].c - temp;
  }
 
  // This will return the answer for each query.
  // Here we consider query's interval as [x, y)
  Node segment(int x, int y, int id, int l, int r, String s) {
    // If the given interval is out of range
    if (l >= y || x >= r) {
      Node temp = new Node();
      temp.t = 0;
      temp.o = 0;
      temp.c = 0;
      return temp;
    }
 
    // If the given interval completely lies
    if (x <= l && r <= y) {
      return tree_arr[id];
    }
 
    // Next three lines are common for
    // any segment tree.
    int mid = (l + r) / 2;
 
    // For left tree
    Node a = segment(x, y, 2 * id, l, mid, s);
    // For right tree
    Node b = segment(x, y, 2 * id + 1, mid, r, s);
    int temp = Math.min(a.o, b.c);
    Node res = new Node();
    res.t = a.t + b.t + temp;
    res.o = a.o + b.o - temp;
    res.c = a.c + b.c - temp;
    return res;
  }
 
  // Driver code
  public static void main(String[] args) {
 
    String s = "((())(()";
    int n = s.length();
    SegmentTree obj = new SegmentTree(n);
    obj.build(1, 0, n, s);
    int a = 3, b = 8;
    Node p = obj.segment(a - 1, b, 1, 0, n, s);
    System.out.println(p.t);
  }
}
 
// This code is contributed by Potta Lokesh


Python3




# Python3 code to find the number of pairs
# involved in balanced parentheses
 
# Our struct node
class node :
    def __init__(self):
        # three variables required
        self.t = 0
        self.o = 0
        self.c = 0
 
# Declare array of nodes of very big
# size which acts as segment tree here.
tree_arr = [node()]*(5 * 1000)
 
# To build asegmenttree we pass 1 as
# 'id' 0 as 'l' and l as 'n'.
# Here, we consider query's interval as [x, y)
def build(id, l, r, s):
    global tree_arr
     
    tree_arr[id] = node()
     
    # this base condition is common to
    # build any segment tree
    # This is the base
    # Only one element left
    if (r - l < 2) :
         
        # If that element is open bracket
        if (s[l] == "("):
            tree_arr[id].o = 1
         
        # If that element is open bracket
        else:
            tree_arr[id].c = 1
        return
 
    # Next three lines are common
    # for any segment tree.
    mid = int( (l + r) / 2)
     
    # for left tree
    build(2 * id, l, mid, s)
     
    # for right tree
    build(2 * id + 1, mid, r, s)
 
    # Here we take minimum of left tree
    # opening brackets and right tree
    # closing brackets
    tmp = min(tree_arr[2 * id].o,
                tree_arr[2 * id + 1].c)
    # we add that to our answer.
    tree_arr[id].t = tree_arr[2 * id].t + \
                    tree_arr[2 * id + 1].t + tmp
 
    # Remove the answer from opening brackets
    tree_arr[id].o = tree_arr[2 * id].o + \
                    tree_arr[2 * id + 1].o - tmp
 
    # Remove the answer from opening brackets
    tree_arr[id].c = tree_arr[2 * id].c + \
                    tree_arr[2 * id + 1].c - tmp
 
# This will return the answer for each query.
# Here we consider query's interval as [x, y)
def segment(x, y, id, l, r, s):
     
    global tree_arr
     
    # If the given interval is out of range
    if (l >= y or x >= r) :
        tem= node()
        tem.t = 0
        tem.o = 0
        tem.c = 0
        return tem
     
    # If the given interval completely lies
    if (x <= l and r <= y):
        return tree_arr[id]
 
    # Next three lines are common for
    # any segment tree.
    mid = int((l + r) / 2)
     
    # For left tree
    a = segment(x, y, 2 * id, l, mid, s)
     
    # For right tree
    b = segment(x, y, 2 * id + 1, mid, r, s)
 
    # Same as made in build function
    temp= 0
    temp = min(a.o, b.c)
    vis = node()
     
    vis.t = a.t + b.t + temp
    vis.o = a.o + b.o - temp
    vis.c = a.c + b.c - temp
    return vis
 
# Driver code
 
s = "((())(()"
n = len(s)
 
# range for query
a = 3
b = 8
     
build(1, 0, n, s)
     
# Here we consider query's interval as [a, b)
# We subtract 1 from 'a' because indexes start
# from 0.
p = segment(a-1, b, 1, 0, n, s)
print(p.t )
 
# This code is contributed by Arnab Kundu


C#




using System;
 
class SegmentTree {
    public Node[] tree_arr;
 
    // Our struct node
    public struct Node { public int t, o, c; }
 
    // Declare array of nodes of very big size which acts as
    // segment tree here.
    public SegmentTree(int n)
    {
        tree_arr = new Node[5 * n];
        for (int i = 0; i < 5 * n; i++) {
            tree_arr[i] = new Node();
        }
    }
 
    // To build a segment tree we pass 1 as 'id' 0 as 'l'
    // and l as 'n'. Here, we consider query's interval as
    // [x, y)
    public void build(int id, int l, int r, string s)
    {
        /* this base condition is common to
               build any segment tree*/
        // This is the base
        // Only one element left
        if (r - l < 2) {
            // If that element is open bracket
            if (s[l] == '(') {
                tree_arr[id].o = 1;
            }
            else {
                tree_arr[id].c = 1;
            }
            return;
        }
 
        // Next three lines are common
        // for any segment tree.
        int mid = (l + r) / 2;
 
        // for left tree
        build(2 * id, l, mid, s);
 
        // for right tree
        build(2 * id + 1, mid, r, s);
 
        // Here we take minimum of left tree opening
        // brackets and right tree closing brackets
        int temp = Math.Min(tree_arr[2 * id].o,
                            tree_arr[2 * id + 1].c);
 
        // we add that to our answer.
        tree_arr[id].t = tree_arr[2 * id].t
                         + tree_arr[2 * id + 1].t + temp;
 
        // Remove the answer from opening brackets
        tree_arr[id].o = tree_arr[2 * id].o
                         + tree_arr[2 * id + 1].o - temp;
 
        // Remove the answer from opening brackets
        tree_arr[id].c = tree_arr[2 * id].c
                         + tree_arr[2 * id + 1].c - temp;
    }
 
    // This will return the answer for each query.
    // Here we consider query's interval as [x, y)
    public Node segment(int x, int y, int id, int l, int r,
                        string s)
    {
        // If the given interval is out of range
        if (l >= y || x >= r) {
            Node temp = new Node();
            temp.t = 0;
            temp.o = 0;
            temp.c = 0;
            return temp;
        }
 
        // If the given interval completely lies
        if (x <= l && r <= y) {
            return tree_arr[id];
        }
 
        // Next three lines are common for
        // any segment tree.
        int mid = (l + r) / 2;
 
        // For left tree
        Node a = segment(x, y, 2 * id, l, mid, s);
        // For right tree
        Node b = segment(x, y, 2 * id + 1, mid, r, s);
        int te = Math.Min(a.o, b.c);
        Node res = new Node();
        res.t = a.t + b.t + te;
        res.o = a.o + b.o - te;
        res.c = a.c + b.c - te;
        return res;
    }
 
    // Driver code
    public static void Main(string[] args)
    {
 
        string s = "((())(()";
        int n = s.Length;
        SegmentTree obj = new SegmentTree(n);
        obj.build(1, 0, n, s);
        int a = 3, b = 8;
        Node p = obj.segment(a - 1, b, 1, 0, n, s);
        Console.WriteLine(p.t);
    }
}


Javascript




// Our struct node
function node() {
     
    // three variables required
    this.t = 0;
    this.o = 0;
    this.c = 0;
}
 
// Declare array of nodes of very big
// size which acts as segment tree here.
let tree_arr = new Array(5 * 1000);
 
// To build a segment tree we pass 1 as
// 'id' 0 as 'l' and l as 'n'.
// Here, we consider query's interval as [x, y)
function build(id, l, r, s)
{
    /* this base condition is common to
       build any segment tree*/
    // This is the base
    // Only one element left
    if (r - l < 2) {
         
        // If that element is open bracket
        if (s[l] == '(')
            tree_arr[id].o = 1;
         
        // If that element is open bracket
        else
            tree_arr[id].c = 1;
        return;
    }
 
    // Next three lines are common
    // for any segment tree.
    let mid = Math.floor((l + r) / 2);
     
    // for left tree
    build(2 * id, l, mid, s);
     
    // for right tree
    build(2 * id + 1, mid, r, s);
 
    // Here we take minimum of left tree
    // opening brackets and right tree
    // closing brackets
    let tmp = Math.min(tree_arr[2 * id].o,
                  tree_arr[2 * id + 1].c);
 
    // we add that to our answer.
    tree_arr[id].t = tree_arr[2 * id].t +
              tree_arr[2 * id + 1].t + tmp;
 
    // Remove the answer from opening brackets
    tree_arr[id].o = tree_arr[2 * id].o +
               tree_arr[2 * id + 1].o - tmp;
 
    // Remove the answer from opening brackets
    tree_arr[id].c = tree_arr[2 * id].c +
               tree_arr[2 * id + 1].c - tmp;
}
 
// This will return the answer for each query.
// Here we consider query's interval as [x, y)
function segment(x, y, id,
             l, r, s)
{
    // If the given interval is out of range
    if (l >= y || x >= r) {
        let tem = new node();
        return tem;
    }
 
    // If the given interval completely lies
    if (x <= l && r <= y)
        return tree_arr[id];
 
    // Next three lines are common for
    // any segment tree.
    let mid = Math.floor((l + r) / 2);
     
    // For left tree
    let a =
           segment(x, y, 2 * id, l, mid, s);
     
    // For right tree
    let b =
           segment(x, y, 2 * id + 1, mid, r, s);
 
    // Same as made in build function
    let temp;
    temp = Math.min(a.o, b.c);
    let vis = new node();
    vis.t = a.t + b.t + temp;
    vis.o = a.o + b.o - temp;
    vis.c = a.c + b.c - temp;
 
    return vis;
}
 
// Driver code
function main()
{
    let s = "((())(()";
    let n = s.length;
 
    // range for query
    let a = 3, b = 8;
     
    build(1, 0, n, s);
     
    // Here we consider query's interval as [a, b)
    // We subtract 1 from 'a' because indexes start
    // from 0.
    let p = segment(a-1, b, 1, 0, n, s);
    console.log(p.t);
     
    return 0;
}
 
main();


Output

2

Time Complexity: O(N), where N is the length of the string.
Auxiliary Space: O(N), for storing the segment tree.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads