Remove Invalid Parentheses
Given a string str consisting only of lowercase letters and the characters '(' and ')'. Your task is to delete minimum parentheses so that the resulting string is balanced, i.e., every opening parenthesis has a matching closing parenthesis in the correct order, and no extra closing parentheses appear. Print all distinct strings you can obtain by performing the minimum number of removals.
Examples:
Input: str = "()())()"
Output: "()()()" "(())()"
Explanation: We can remove the closing bracket at index 3 to obtain the balanced string "()()()". Similarly, we can remove the closing bracket at index 1 to obtain the balanced string "(())()".Input: str = "(v)())()"
Output: "(v)()()" "(v())()"
Explanation: The given string is the modified version of first string containing a letter 'v' . As the letters do not differ the parentheses, the solution remains the same.Input: S = ")("
Output: ""
Using Breadth First Search - O(2 ^ n) Time and O(2 ^ n) Space
The idea is to remove brackets one by one and check for balance. To remove brackets in a systematic way, we use BFS order. We remove one bracket at a time, check for balance, then remove more brackets and again check in BFS manner. We stop when we find a balanced string.
One important observation about this problem is, we can check the balancing by simply counting opening and closing brackets because we have only one type of brackets. We do not need to use stack to check.
Follow the below given steps:
- Initialize an empty
visit
map, a queueq
, a result vectorres
, and a booleanlevel = false
. - Push the original
str
intoq
and markvisit[str] = 1
. - While
q
is not empty:- Dequeue
temp
fromq
. - If
isValidString(temp)
returns true:- Append
temp
tores
. - Set
level = true
.
- Append
- If
level
is true, skip further removals at this depth and continue. - Otherwise, for each index
i
intemp
wheretemp[i]
is ‘(’ or ‘)’:- Form
cur = temp.substr(0, i) + temp.substr(i + 1)
. - If
visit.count(cur) == 0
, enqueuecur
intoq
and setvisit[cur] = 1
.
- Form
- Dequeue
- Return
res
.
Below is given the implementation:
#include <bits/stdc++.h>
using namespace std;
// method returns true if string
// contains valid parenthesis
bool isValidString(string str) {
int cnt = 0;
for (int i = 0; i < str.length(); i++) {
if (str[i] == '(')
cnt++;
else if (str[i] == ')')
cnt--;
if (cnt < 0)
return false;
}
return (cnt == 0);
}
// function to remove invalid parenthesis
vector<string> validParenthesis(string &str) {
// to ignore already visited string
unordered_map<string, int> visit;
// queue to maintain BFS
queue<string> q;
// to store the valid strings
vector<string> res;
bool level = false;
// pushing given string as starting node into queue
q.push(str);
// mark the string as visited
visit[str] = 1;
// while queue is not empty
while (!q.empty()) {
string temp = q.front();
q.pop();
// check if the string is valid
if (isValidString(temp)) {
// if valid, store it
res.push_back(temp);
// make level true, so that valid string
// of only that level are processed.
level = true;
}
if (level)
continue;
for (int i = 0; i < temp.length(); i++) {
// if current character is not a parenthesis
// continue to next character
if (temp[i] != '(' && temp[i] != ')')
continue;
// Removing parenthesis from str and
// pushing into queue,if not visited already
string cur = temp.substr(0, i) + temp.substr(i + 1);
if (visit.count(cur) == 0) {
q.push(cur);
visit[cur] = 1;
}
}
}
return res;
}
int main() {
string str = "(v)())()";
vector<string> res = validParenthesis(str);
for (string s : res) {
cout << s << endl;
}
return 0;
}
import java.util.*;
class GfG {
// method returns true if string
// contains valid parenthesis
static boolean isValidString(String str) {
int cnt = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '(')
cnt++;
else if (str.charAt(i) == ')')
cnt--;
if (cnt < 0)
return false;
}
return (cnt == 0);
}
// function to remove invalid parenthesis
static List<String> validParenthesis(String str) {
// to ignore already visited string
HashMap<String, Integer> visit = new HashMap<>();
// queue to maintain BFS
Queue<String> q = new LinkedList<>();
// to store the valid strings
List<String> res = new ArrayList<>();
boolean level = false;
// pushing given string as starting node into queue
q.add(str);
// mark the string as visited
visit.put(str, 1);
// while queue is not empty
while (!q.isEmpty()) {
String temp = q.poll();
// check if the string is valid
if (isValidString(temp)) {
// if valid, store it
res.add(temp);
// make level true, so that valid string
// of only that level are processed.
level = true;
}
if (level)
continue;
for (int i = 0; i < temp.length(); i++) {
// if current character is not a parenthesis
// continue to next character
if (temp.charAt(i) != '(' && temp.charAt(i) != ')')
continue;
// Removing parenthesis from str and
// pushing into queue,if not visited already
String cur = temp.substring(0, i) + temp.substring(i + 1);
if (!visit.containsKey(cur)) {
q.add(cur);
visit.put(cur, 1);
}
}
}
return res;
}
public static void main(String[] args) {
String str = "(v)())()";
List<String> res = validParenthesis(str);
for (String s : res) {
System.out.println(s);
}
}
}
from collections import deque
# method returns true if string
# contains valid parenthesis
def isValidString(str):
cnt = 0
for i in range(len(str)):
if str[i] == '(':
cnt += 1
elif str[i] == ')':
cnt -= 1
if cnt < 0:
return False
return cnt == 0
# function to remove invalid parenthesis
def validParenthesis(str):
# to ignore already visited string
visit = {}
# queue to maintain BFS
q = deque()
# to store the valid strings
res = []
level = False
# pushing given string as starting node into queue
q.append(str)
# mark the string as visited
visit[str] = 1
# while queue is not empty
while q:
temp = q.popleft()
# check if the string is valid
if isValidString(temp):
# if valid, store it
res.append(temp)
# make level true, so that valid string
# of only that level are processed.
level = True
if level:
continue
for i in range(len(temp)):
# if current character is not a parenthesis
# continue to next character
if temp[i] != '(' and temp[i] != ')':
continue
# Removing parenthesis from str and
# pushing into queue,if not visited already
cur = temp[:i] + temp[i + 1:]
if cur not in visit:
q.append(cur)
visit[cur] = 1
return res
str = "(v)())()"
res = validParenthesis(str)
for s in res:
print(s)
using System;
using System.Collections.Generic;
class GfG {
// method returns true if string
// contains valid parenthesis
static bool isValidString(string str) {
int cnt = 0;
for (int i = 0; i < str.Length; i++) {
if (str[i] == '(')
cnt++;
else if (str[i] == ')')
cnt--;
if (cnt < 0)
return false;
}
return cnt == 0;
}
// function to remove invalid parenthesis
static List<string> validParenthesis(string str) {
// to ignore already visited string
Dictionary<string, int> visit = new Dictionary<string, int>();
// queue to maintain BFS
Queue<string> q = new Queue<string>();
// to store the valid strings
List<string> res = new List<string>();
bool level = false;
// pushing given string as starting node into queue
q.Enqueue(str);
// mark the string as visited
visit[str] = 1;
// while queue is not empty
while (q.Count > 0) {
string temp = q.Dequeue();
// check if the string is valid
if (isValidString(temp)) {
// if valid, store it
res.Add(temp);
// make level true, so that valid string
// of only that level are processed.
level = true;
}
if (level)
continue;
for (int i = 0; i < temp.Length; i++) {
// if current character is not a parenthesis
// continue to next character
if (temp[i] != '(' && temp[i] != ')')
continue;
// Removing parenthesis from str and
// pushing into queue,if not visited already
string cur = temp.Substring(0, i) + temp.Substring(i + 1);
if (!visit.ContainsKey(cur)) {
q.Enqueue(cur);
visit[cur] = 1;
}
}
}
return res;
}
static void Main() {
string str = "(v)())()";
List<string> res = validParenthesis(str);
foreach (string s in res) {
Console.WriteLine(s);
}
}
}
// method returns true if string
// contains valid parenthesis
function isValidString(str) {
let cnt = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === '(')
cnt++;
else if (str[i] === ')')
cnt--;
if (cnt < 0)
return false;
}
return cnt === 0;
}
// function to remove invalid parenthesis
function validParenthesis(str) {
// to ignore already visited string
let visit = {};
// queue to maintain BFS
let q = [];
// to store the valid strings
let res = [];
let level = false;
// pushing given string as starting node into queue
q.push(str);
// mark the string as visited
visit[str] = 1;
// while queue is not empty
while (q.length > 0) {
let temp = q.shift();
// check if the string is valid
if (isValidString(temp)) {
// if valid, store it
res.push(temp);
// make level true, so that valid string
// of only that level are processed.
level = true;
}
if (level)
continue;
for (let i = 0; i < temp.length; i++) {
// if current character is not a parenthesis
// continue to next character
if (temp[i] !== '(' && temp[i] !== ')')
continue;
// Removing parenthesis from str and
// pushing into queue,if not visited already
let cur = temp.substring(0, i) + temp.substring(i + 1);
if (!(cur in visit)) {
q.push(cur);
visit[cur] = 1;
}
}
}
return res;
}
let str = "(v)())()";
let res = validParenthesis(str);
for (let s of res) {
console.log(s);
}
Output
(v())() (v)()()
Time Complexity: O(2 ^ n), the worst‐case time complexity is exponential, namely O(2ⁿ), since BFS may explore up to two options (remove or keep) at each of the n positions.
Space Complexity: O(2 ^ n), since both the BFS queue and the visited‐strings set can each grow to store up to 2ⁿ distinct strings.
Using Depth First Search - O(2 ^ n) Time and O(2 ^ n) Space
We first determine how many opening
(
and closing)
parentheses are invalid and need to be removed. Then, use a recursive function to explore all ways of removing these parentheses while maintaining balance between open and close brackets. At each step, either skip a parenthesis (if it's invalid) or include it in the current string (if it helps form a valid expression), and continue building the string. Only strings that end with no unmatched parentheses are collected as valid results.
Below is given the step-by-step approach:
- Count how many open
(
and close)
parentheses are invalid in the input stringstr
. - Create a set
result
to store all valid strings without duplicates. - Define a recursive function
findValid
that:- Takes current index, counts of invalid open and close parentheses, currently unmatched open pairs (
pair
), the current constructed stringcur
, and the result setres
. - If the current character is not a parenthesis, simply add it to
cur
and move to the next index. - If the current character is
(
:- If invalid open count is more than zero, skip this character and decrement
open
. - Also, try including it and increment the
pair
count.
- If invalid open count is more than zero, skip this character and decrement
- If the current character is
)
:- If invalid close count is more than zero, skip this character and decrement
close
. - If
pair
is more than zero, include this character and decrementpair
.
- If invalid close count is more than zero, skip this character and decrement
- If end of string is reached, check if all invalid counts (
open
,close
) andpair
are zero. If so, addcur
to the result set.
- Takes current index, counts of invalid open and close parentheses, currently unmatched open pairs (
- After recursion completes, convert the result set to a list and return it.
Below is given the implementation:
#include <bits/stdc++.h>
using namespace std;
// recursive function to find all valid strings
void findValid(string str, int index, int open, int close,
int pair, string cur, unordered_set<string> &res) {
// base case, if end of string is reached
if (index == str.size()) {
// check if all open and closed invalid
// parenthesis are removed and no pair is left
if (open == 0 && close == 0 && pair == 0) {
// if so, store the string
res.insert(cur);
}
return;
}
// if the current character is not a parenthesis
if (str[index] != '(' && str[index] != ')') {
// add the character to the current string
findValid(str, index + 1, open, close,
pair, cur + str[index], res);
}
else {
// if the current character is an open bracket
if (str[index] == '(') {
// reduce open count by 1,
// and skip current character
if (open > 0) {
findValid(str, index + 1, open - 1,
close, pair, cur, res);
}
// add the current character to the string
findValid(str, index + 1, open, close,
pair + 1, cur + str[index], res);
}
// else if the current character is a closed bracket
else {
// skip current character and
// reduce closed count by 1
if (close > 0)
findValid(str, index + 1, open,
close - 1, pair, cur, res);
// if there is an open pair, reduce
// it and add the current character
if (pair > 0)
findValid(str, index + 1, open, close,
pair - 1, cur + str[index], res);
}
}
}
vector<string> validParenthesis(string &str) {
// to store the unique valid strings
unordered_set<string> result;
// to store count of invalid
// open and closed paraenthesis
int open = 0, close = 0;
// count the number of invalid
// open and closed parenthesis
for (auto c : str) {
// if open bracket, increase
// open invalid count by 1
if (c == '(')
open++;
// if closed bracket,
if (c == ')') {
// decrement invalid open
// count by 1 if open is not 0
if (open != 0)
open--;
// else increment invalid closed
// bracket count by 1
else
close++;
}
}
// recursive function to find all valid strings
findValid(str, 0, open, close, 0, "", result);
// store the unique strings in an array
vector<string> res(result.begin(), result.end());
return res;
}
int main() {
string str = "(v)())()";
vector<string> res = validParenthesis(str);
for (string s : res) {
cout << s << endl;
}
return 0;
}
import java.util.*;
public class GfG {
// recursive function to find all valid strings
public static void findValid(String str, int index, int open, int close,
int pair, String cur, Set<String> res) {
// base case, if end of string is reached
if (index == str.length()) {
// check if all open and closed invalid
// parenthesis are removed and no pair is left
if (open == 0 && close == 0 && pair == 0) {
// if so, store the string
res.add(cur);
}
return;
}
// if the current character is not a parenthesis
if (str.charAt(index) != '(' && str.charAt(index) != ')') {
// add the character to the current string
findValid(str, index + 1, open, close,
pair, cur + str.charAt(index), res);
}
else {
// if the current character is an open bracket
if (str.charAt(index) == '(') {
// reduce open count by 1,
// and skip current character
if (open > 0) {
findValid(str, index + 1, open - 1,
close, pair, cur, res);
}
// add the current character to the string
findValid(str, index + 1, open, close,
pair + 1, cur + str.charAt(index), res);
}
// else if the current character is a closed bracket
else {
// skip current character and
// reduce closed count by 1
if (close > 0)
findValid(str, index + 1, open,
close - 1, pair, cur, res);
// if there is an open pair, reduce
// it and add the current character
if (pair > 0)
findValid(str, index + 1, open, close,
pair - 1, cur + str.charAt(index), res);
}
}
}
public static List<String> validParenthesis(String str) {
// to store the unique valid strings
Set<String> result = new HashSet<>();
// to store count of invalid
// open and closed paraenthesis
int open = 0, close = 0;
// count the number of invalid
// open and closed parenthesis
for (char c : str.toCharArray()) {
// if open bracket, increase
// open invalid count by 1
if (c == '(')
open++;
// if closed bracket,
if (c == ')') {
// decrement invalid open
// count by 1 if open is not 0
if (open != 0)
open--;
// else increment invalid closed
// bracket count by 1
else
close++;
}
}
// recursive function to find all valid strings
findValid(str, 0, open, close, 0, "", result);
// store the unique strings in an array
List<String> res = new ArrayList<>(result);
return res;
}
public static void main(String[] args) {
String str = "(v)())()";
List<String> res = validParenthesis(str);
for (String s : res) {
System.out.println(s);
}
}
}
# recursive function to find all valid strings
def findValid(str, index, open, close,
pair, cur, res):
# base case, if end of string is reached
if index == len(str):
# check if all open and closed invalid
# parenthesis are removed and no pair is left
if open == 0 and close == 0 and pair == 0:
# if so, store the string
res.add(cur)
return
# if the current character is not a parenthesis
if str[index] != '(' and str[index] != ')':
# add the character to the current string
findValid(str, index + 1, open, close,
pair, cur + str[index], res)
else:
# if the current character is an open bracket
if str[index] == '(':
# reduce open count by 1,
# and skip current character
if open > 0:
findValid(str, index + 1, open - 1,
close, pair, cur, res)
# add the current character to the string
findValid(str, index + 1, open, close,
pair + 1, cur + str[index], res)
# else if the current character is a closed bracket
else:
# skip current character and
# reduce closed count by 1
if close > 0:
findValid(str, index + 1, open,
close - 1, pair, cur, res)
# if there is an open pair, reduce
# it and add the current character
if pair > 0:
findValid(str, index + 1, open, close,
pair - 1, cur + str[index], res)
def validParenthesis(str):
# to store the unique valid strings
result = set()
# to store count of invalid
# open and closed paraenthesis
open = 0
close = 0
# count the number of invalid
# open and closed parenthesis
for c in str:
# if open bracket, increase
# open invalid count by 1
if c == '(':
open += 1
# if closed bracket,
if c == ')':
# decrement invalid open
# count by 1 if open is not 0
if open != 0:
open -= 1
# else increment invalid closed
# bracket count by 1
else:
close += 1
# recursive function to find all valid strings
findValid(str, 0, open, close, 0, "", result)
# store the unique strings in an array
return list(result)
if __name__ == "__main__":
str = "(v)())()"
res = validParenthesis(str)
for s in res:
print(s)
using System;
using System.Collections.Generic;
public class GfG {
// recursive function to find all valid strings
public static void findValid(string str, int index, int open, int close,
int pair, string cur, HashSet<string> res) {
// base case, if end of string is reached
if (index == str.Length) {
// check if all open and closed invalid
// parenthesis are removed and no pair is left
if (open == 0 && close == 0 && pair == 0) {
// if so, store the string
res.Add(cur);
}
return;
}
// if the current character is not a parenthesis
if (str[index] != '(' && str[index] != ')') {
// add the character to the current string
findValid(str, index + 1, open, close,
pair, cur + str[index], res);
}
else {
// if the current character is an open bracket
if (str[index] == '(') {
// reduce open count by 1,
// and skip current character
if (open > 0) {
findValid(str, index + 1, open - 1,
close, pair, cur, res);
}
// add the current character to the string
findValid(str, index + 1, open, close,
pair + 1, cur + str[index], res);
}
// else if the current character is a closed bracket
else {
// skip current character and
// reduce closed count by 1
if (close > 0)
findValid(str, index + 1, open,
close - 1, pair, cur, res);
// if there is an open pair, reduce
// it and add the current character
if (pair > 0)
findValid(str, index + 1, open, close,
pair - 1, cur + str[index], res);
}
}
}
public static List<string> validParenthesis(string str) {
// to store the unique valid strings
HashSet<string> result = new HashSet<string>();
// to store count of invalid
// open and closed paraenthesis
int open = 0, close = 0;
// count the number of invalid
// open and closed parenthesis
foreach (char c in str) {
// if open bracket, increase
// open invalid count by 1
if (c == '(')
open++;
// if closed bracket,
if (c == ')') {
// decrement invalid open
// count by 1 if open is not 0
if (open != 0)
open--;
// else increment invalid closed
// bracket count by 1
else
close++;
}
}
// recursive function to find all valid strings
findValid(str, 0, open, close, 0, "", result);
// store the unique strings in an array
List<string> res = new List<string>(result);
return res;
}
public static void Main() {
string str = "(v)())()";
List<string> res = validParenthesis(str);
foreach (string s in res) {
Console.WriteLine(s);
}
}
}
// recursive function to find all valid strings
function findValid(str, index, open, close,
pair, cur, res) {
// base case, if end of string is reached
if (index === str.length) {
// check if all open and closed invalid
// parenthesis are removed and no pair is left
if (open === 0 && close === 0 && pair === 0) {
// if so, store the string
res.add(cur);
}
return;
}
// if the current character is not a parenthesis
if (str[index] !== '(' && str[index] !== ')') {
// add the character to the current string
findValid(str, index + 1, open, close,
pair, cur + str[index], res);
}
else {
// if the current character is an open bracket
if (str[index] === '(') {
// reduce open count by 1,
// and skip current character
if (open > 0) {
findValid(str, index + 1, open - 1,
close, pair, cur, res);
}
// add the current character to the string
findValid(str, index + 1, open, close,
pair + 1, cur + str[index], res);
}
// else if the current character is a closed bracket
else {
// skip current character and
// reduce closed count by 1
if (close > 0)
findValid(str, index + 1, open,
close - 1, pair, cur, res);
// if there is an open pair, reduce
// it and add the current character
if (pair > 0)
findValid(str, index + 1, open, close,
pair - 1, cur + str[index], res);
}
}
}
function validParenthesis(str) {
// to store the unique valid strings
let result = new Set();
// to store count of invalid
// open and closed paraenthesis
let open = 0, close = 0;
// count the number of invalid
// open and closed parenthesis
for (let c of str) {
// if open bracket, increase
// open invalid count by 1
if (c === '(')
open++;
// if closed bracket,
if (c === ')') {
// decrement invalid open
// count by 1 if open is not 0
if (open !== 0)
open--;
// else increment invalid closed
// bracket count by 1
else
close++;
}
}
// recursive function to find all valid strings
findValid(str, 0, open, close, 0, "", result);
// store the unique strings in an array
return Array.from(result);
}
let str = "(v)())()";
let res = validParenthesis(str);
for (let s of res) {
console.log(s);
}
Output
(v)()() (v())()