Longest Balanced Subsequence
Given a string str, find the length of the longest balanced subsequence in it. A balanced string is defined as a string sequence that can form a valid balanced expression, consisting of matching opening and closing brackets.
- A null string is a balanced string.
- If X and Y are balanced strings, then (X)Y and XY are balanced strings.
Examples:
Input: str = "()())"
Output: 4
Explanation: ()() is the longest balanced subsequence of length 4.Input: str = "()(((((()"
Output : 4
Explanation: The first and last two characters forms the subsequence "()()", which is the longest balanced subsequence of length 4.
Table of Content
[Naive Approach] - Simple Recursive - O(2 ^ n) Time and O(1) Space
The idea is to compare the corner characters of the given string. If they match then recur for the remaining substring and add 2 to the result. Else, try all possible combinations from two substrings from i to k and k + 1 to j where k goes from i to j - 1.
LBS of substring str[i..j] (Initially i = 0, j = length of string - 1) :
If str[i] == "(" and str[j] == ")"
LBS(str, i, j) = LBS(str, i + 1, j - 1) + 2
Else
LBS(str, i, j) = max(LBS(str, i, k) + LBS(str, k + 1, j)) Where i <= k < j
#include <iostream>
using namespace std;
int LBS(string &s, int i, int j) {
if (i > j) return 0;
// If corner characters form a balance
if (s[i] == '(' && s[j] == ')')
return LBS(s, i + 1, j - 1) + 2;
// Else try putting a break at every index
int res = 0;
for (int k = i; k < j; k++)
res = max(res, LBS(s, i, k) + LBS(s, k + 1, j));
return res;
}
int main() {
string s = "(()())";
cout << "Longest Balanced Subsequence: "
<< LBS(s, 0, s.size() - 1) << endl;
return 0;
}
public class Main {
public static int LBS(String s, int i, int j) {
if (i > j) return 0;
// If corner characters form a balance
if (s.charAt(i) == '(' && s.charAt(j) == ')')
return LBS(s, i + 1, j - 1) + 2;
// Else try putting a break at every index
int res = 0;
for (int k = i; k < j; k++)
res = Math.max(res, LBS(s, i, k) + LBS(s, k + 1, j));
return res;
}
public static void main(String[] args) {
String s = "(()())";
System.out.println("Longest Balanced Subsequence: " + LBS(s, 0, s.length() - 1));
}
}
def LBS(s, i, j):
if i > j:
return 0
# If corner characters form a balance
if s[i] == '(' and s[j] == ')':
return LBS(s, i + 1, j - 1) + 2
# Else try putting a break at every index
res = 0
for k in range(i, j):
res = max(res, LBS(s, i, k) + LBS(s, k + 1, j))
return res
s = '(()())'
print('Longest Balanced Subsequence:', LBS(s, 0, len(s) - 1))
using System;
class Program {
public static int LBS(string s, int i, int j) {
if (i > j) return 0;
// If corner characters form a balance
if (s[i] == '(' && s[j] == ')')
return LBS(s, i + 1, j - 1) + 2;
// Else try putting a break at every index
int res = 0;
for (int k = i; k < j; k++)
res = Math.Max(res, LBS(s, i, k) + LBS(s, k + 1, j));
return res;
}
static void Main() {
string s = "(()())";
Console.WriteLine("Longest Balanced Subsequence: " + LBS(s, 0, s.Length - 1));
}
}
function LBS(s, i, j) {
if (i > j) return 0;
// If corner characters form a balance
if (s[i] === '(' && s[j] === ')')
return LBS(s, i + 1, j - 1) + 2;
// Else try putting a break at every index
let res = 0;
for (let k = i; k < j; k++)
res = Math.max(res, LBS(s, i, k) + LBS(s, k + 1, j));
return res;
}
const s = '(()())';
console.log('Longest Balanced Subsequence:', LBS(s, 0, s.length - 1));
[Better Approach] - Using Dynamic Programming - O(n ^ 3) Time and O(n ^ 2) Space
If we take a closer look at the above recursive solution, we can notice that it is similar to Matrix Chain Multiplication. So the solution has both optimial substructure and overlapping subproblems.
So we solve this problem using Dynamic programming. We build a 2D table that captures the length of the longest balanced subsequence for every substring and then use that table to compute the final answer. To do so, create a 2d array dp[][] of order n * n, where dp[i][j] stores the longest balanced subsequence in substring str[i..j].
Now, for any substring str[i...j], if str[i] = '(' and str[j] = ')', then set dp[i][j] = 2 + dp[i+1][j-1], i.e. length of longest balanced subsequence of substring str[i+1....j-1] + current 2 characters. Also, run a loop from i to j - 1 to check for all possible split, i.e. set dp[i][j] to max of dp[i][j] and dp[i][k] + dp[k + 1][j].
Follow the below given steps:
- Create a 2D matrix dp[][] where dp[i][j] represents the length of the longest balanced subsequence in the substring str[i..j].
- Process the substrings in order of increasing length (i.e. increasing j - i).
- For each substring str[i..j]:
- If str[i] is '(' and str[j] is ')', then set dp[i][j] = dp[i+1][j-1] + 2 because these two matching characters contribute to the balanced subsequence.
- Otherwise, try every possible split:
- For each k between i and j-1, compute the sum dp[i][k] + dp[k+1][j].
- Also, consider the cases dp[i+1][j] and dp[i][j-1].
- Set dp[i][j] to the maximum of all these possibilities.
- The final answer is dp[0][length of string - 1] which gives the length of the longest balanced subsequence for the entire string.
#include <bits/stdc++.h>
using namespace std;
// Function to find the length of
// maximum balanced subsequence
int maxBalancedSubseq(string str) {
int n = str.length();
// create a 2d dp array
vector<vector<int>> dp(n, vector<int>(n, 0));
// Considering all balanced
// substrings of length 2
for (int i = 0; i < n - 1; i++) {
if (str[i] == '(' && str[i + 1] == ')') {
dp[i][i + 1] = 2;
}
}
// Considering all other substrings
for (int l = 2; l < n; l++) {
for (int i = 0, j = l; j < n; i++, j++) {
if (str[i] == '(' && str[j] == ')') {
dp[i][j] = 2 + dp[i + 1][j - 1];
}
for (int k = i; k < j; k++) {
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
return dp[0][n - 1];
}
int main() {
string str = "()(((((()";
cout << maxBalancedSubseq(str) << endl;
return 0;
}
// Function to find the length of
// maximum balanced subsequence
import java.util.*;
class GfG {
// Function to find the length of
// maximum balanced subsequence
static int maxBalancedSubseq(String str) {
int n = str.length();
// create a 2d dp array
int[][] dp = new int[n][n];
// Considering all balanced
// substrings of length 2
for (int i = 0; i < n - 1; i++) {
if (str.charAt(i) == '(' && str.charAt(i + 1) == ')') {
dp[i][i + 1] = 2;
}
}
// Considering all other substrings
for (int l = 2; l < n; l++) {
for (int i = 0, j = l; j < n; i++, j++) {
if (str.charAt(i) == '(' && str.charAt(j) == ')') {
dp[i][j] = 2 + dp[i + 1][j - 1];
}
for (int k = i; k < j; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
return dp[0][n - 1];
}
public static void main(String[] args) {
String str = "()(((((()";
System.out.println(maxBalancedSubseq(str));
}
}
# Function to find the length of
# maximum balanced subsequence.
def maxBalancedSubseq(str):
n = len(str)
# create a 2d dp array
dp = [[0 for _ in range(n)] for _ in range(n)]
# Considering all balanced
# substrings of length 2
for i in range(n - 1):
if str[i] == '(' and str[i + 1] == ')':
dp[i][i + 1] = 2
# Considering all other substrings
for l in range(2, n):
for i in range(0, n - l):
j = i + l
if str[i] == '(' and str[j] == ')':
dp[i][j] = 2 + dp[i + 1][j - 1]
for k in range(i, j):
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j])
return dp[0][n - 1]
if __name__ == "__main__":
str = "()(((((()"
print(maxBalancedSubseq(str))
// Function to find the length of
// maximum balanced subsequence.
using System;
using System.Collections.Generic;
class GfG {
// Function to find the length of
// maximum balanced subsequence.
static int maxBalancedSubseq(string str) {
int n = str.Length;
// create a 2d dp array
List<List<int>> dp = new List<List<int>>();
for (int i = 0; i < n; i++) {
List<int> row = new List<int>();
for (int j = 0; j < n; j++) {
row.Add(0);
}
dp.Add(row);
}
// Considering all balanced
// substrings of length 2
for (int i = 0; i < n - 1; i++) {
if (str[i] == '(' && str[i + 1] == ')') {
dp[i][i + 1] = 2;
}
}
// Considering all other substrings
for (int l = 2; l < n; l++) {
for (int i = 0, j = l; j < n; i++, j++) {
if (str[i] == '(' && str[j] == ')') {
dp[i][j] = 2 + dp[i + 1][j - 1];
}
for (int k = i; k < j; k++) {
dp[i][j] = Math.Max(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
return dp[0][n - 1];
}
static void Main() {
string str = "()(((((()";
Console.WriteLine(maxBalancedSubseq(str));
}
}
// Function to find the length of
// maximum balanced subsequence.
function maxBalancedSubseq(str) {
let n = str.length;
// create a 2d dp array
let dp = new Array(n);
for (let i = 0; i < n; i++) {
dp[i] = new Array(n).fill(0);
}
// Considering all balanced
// substrings of length 2
for (let i = 0; i < n - 1; i++) {
if (str[i] === '(' && str[i + 1] === ')') {
dp[i][i + 1] = 2;
}
}
// Considering all other substrings
for (let l = 2; l < n; l++) {
for (let i = 0, j = l; j < n; i++, j++) {
if (str[i] === '(' && str[j] === ')') {
dp[i][j] = 2 + dp[i + 1][j - 1];
}
for (let k = i; k < j; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
return dp[0][n - 1];
}
let str = "()(((((()";
console.log(maxBalancedSubseq(str));
Output
4
[Expected Approach] - O(n) Time and O(1) Space
The idea is to find the count of invalid open and closed braces and return their sum subtracted from size of string.
Follow the below given steps:
- Count the number of braces to be removed to get the longest balanced parentheses sub-sequence.
- If the i-th index number of close braces is greater than the number of open braces, then that close brace has to be removed.
- Count the number of close braces that need to be removed.
- In the end, the number of extra open braces will also be removed.
- So, the total count to be removed would be the sum of extra open braces and invalid close braces.
Below is given the implementation:
#include <bits/stdc++.h>
using namespace std;
// Function to find the length of
// maximum balanced subsequence
int maxBalancedSubseq(string str) {
int n = str.length();
// to count invalid open and close braces
int invalidOpen = 0, invalidClose = 0;
// Iterating over the String
for (int i = 0; i < n; i++) {
// count of open braces that
// hasn't been closed yet
if (str[i] == '(') {
invalidOpen++;
}
else { // Closing bracket
// count of close braces that
// cannot be mapped to any open brace
if (invalidOpen == 0) {
invalidClose++;
}
// Mapping the ith close brace
// to one of the open brace
else {
invalidOpen--;
}
}
}
return n - (invalidOpen + invalidClose);
}
int main() {
string str = "(((((()";
cout << maxBalancedSubseq(str) << endl;
return 0;
}
// Function to find the length of
// maximum balanced subsequence
import java.util.*;
class GfG {
// Function to find the length of
// maximum balanced subsequence
static int maxBalancedSubseq(String str) {
int n = str.length();
// to count invalid open and close braces
int invalidOpen = 0, invalidClose = 0;
// Iterating over the String
for (int i = 0; i < n; i++) {
// count of open braces that
// hasn't been closed yet
if (str.charAt(i) == '(') {
invalidOpen++;
}
else {
// count of close braces that
// cannot be mapped to any open brace
if (invalidOpen == 0) {
invalidClose++;
}
// Mapping the ith close brace
// to one of the open brace
else {
invalidOpen--;
}
}
}
return n - (invalidOpen + invalidClose);
}
public static void main(String[] args) {
String str = "()(((((()";
System.out.println(maxBalancedSubseq(str));
}
}
# Function to find the length of
# maximum balanced subsequence.
def maxBalancedSubseq(str):
n = len(str)
# to count invalid open and close braces
invalidOpen = 0
invalidClose = 0
# Iterating over the String
for i in range(n):
# count of open braces that
# hasn't been closed yet
if str[i] == '(':
invalidOpen += 1
else:
# count of close braces that
# cannot be mapped to any open brace
if invalidOpen == 0:
invalidClose += 1
# Mapping the ith close brace
# to one of the open brace
else:
invalidOpen -= 1
return n - (invalidOpen + invalidClose)
if __name__ == "__main__":
str = "()(((((()"
print(maxBalancedSubseq(str))
// Function to find the length of
// maximum balanced subsequence.
using System;
using System.Collections.Generic;
class GfG {
// Function to find the length of
// maximum balanced subsequence.
static int maxBalancedSubseq(string str) {
int n = str.Length;
// to count invalid open and close braces
int invalidOpen = 0, invalidClose = 0;
// Iterating over the String
for (int i = 0; i < n; i++) {
// count of open braces that
// hasn't been closed yet
if (str[i] == '(') {
invalidOpen++;
}
else {
// count of close braces that
// cannot be mapped to any open brace
if (invalidOpen == 0) {
invalidClose++;
}
// Mapping the ith close brace
// to one of the open brace
else {
invalidOpen--;
}
}
}
return n - (invalidOpen + invalidClose);
}
static void Main() {
string str = "()(((((()";
Console.WriteLine(maxBalancedSubseq(str));
}
}
// Function to find the length of
// maximum balanced subsequence.
function maxBalancedSubseq(str) {
let n = str.length;
// to count invalid open and close braces
let invalidOpen = 0, invalidClose = 0;
// Iterating over the String
for (let i = 0; i < n; i++) {
// count of open braces that
// hasn't been closed yet
if (str[i] === '(') {
invalidOpen++;
}
else {
// count of close braces that
// cannot be mapped to any open brace
if (invalidOpen === 0) {
invalidClose++;
}
// Mapping the ith close brace
// to one of the open brace
else {
invalidOpen--;
}
}
}
return n - (invalidOpen + invalidClose);
}
let str = "()(((((()";
console.log(maxBalancedSubseq(str));
Output
4