Talentd
FleetCode
Make and follow sheets.Sign in

Remove Invalid Parentheses solution and explanation

HardBacktrackingBreadth-First SearchString7 min read52.4% acceptanceUpdated 9 Apr 2026
Remove Invalid Parentheses Explained using Stacks | Leetcode 301 (Valid Parentheses) Code in JAVAPepcoding · 23:20 · 39K viewsWatch on YouTube
9 more videos on this problem
  1. Remove Invalid Parentheses Explained using Stacks | Leetcode 301 (Valid Parentheses) Code in JAVAPepcoding · 23:20 · 39K views
  2. 花花酱 LeetCode 301. Remove Invalid Parentheses - 刷题找工作 EP139Hua Hua · 22:36 · 30K views
  3. REMOVE INVALID PARENTHESIS | LEETCODE # 301 | PYTHON BACKTRACKING SOLUTIONCracking FAANG · 19:55 · 17K views
  4. Remove Invalid Parentheses | Leetcode 301 | C++Ayushi Sharma · 15:58 · 14K views
  5. LeetCode 301. Remove Invalid Parentheses Explanation and Solutionhappygirlzt · 15:40 · 14K views
  6. Facebook Coding Interview Question | Leetcode 301 | Remove Invalid ParenthesesWorkWithGoogler · 30:18 · 5K views
  7. 301. Remove Invalid Parentheses (Leetcode Hard)Programming Live with Larry · 1:15:44 · 1K views
  8. Leetcode 301 remove invalid parentheses (best solution)leetcode_fun · 5:27 · 1K views
  9. Remove invalid Parentheses | Leetcode 301 | BFSComtra : Code - Music - Travel - Photography · 12:06 · 884 views
  10. LeetCode 301. Remove Invalid Parentheses Solution Explained - JavaAlgorithms and Data Structures Course · 21:05 · 648 views

The problem

Given a string s that contains parentheses and letters, remove the minimum number of invalid parentheses to make the input string valid.

Return a list of unique strings that are valid with the minimum number of removals. You may return the answer in any order.

Example 1:

Input: s = "()())()"
Output: ["(())()","()()()"]

Example 2:

Input: s = "(a)())()"
Output: ["(a())()","(a)()()"]

Example 3:

Input: s = ")("
Output: [""]

Constraints:

  • 1 <= s.length <= 25
  • s consists of lowercase English letters and parentheses '(' and ')'.
  • There will be at most 20 parentheses in s.

Approach overview

Problem Overview: Given a string containing letters and parentheses, remove the minimum number of invalid parentheses so the resulting string becomes valid. Return all possible valid results without duplicates.

Approach 1: Breadth-First Search (BFS) (Time: O(2^n), Space: O(2^n))

The BFS approach treats each string as a node in a search graph. Start with the original string and generate the next level by removing one parenthesis at every possible position. For each generated string, check validity using a counter: increment for (, decrement for ), and ensure the count never drops below zero. The key insight is that BFS explores by number of removals. As soon as valid strings appear at a level, stop exploring deeper levels because they would require more removals than necessary. Use a queue for traversal and a set to avoid revisiting strings. This guarantees the results contain the minimum number of removals. The method works well for problems where the smallest transformation must be discovered first. Concepts rely heavily on Breadth-First Search and efficient string manipulation.

Approach 2: Depth-First Search with Backtracking (Time: O(2^n), Space: O(2^n))

This method first calculates how many left and right parentheses must be removed. Then perform a DFS that decides for each character whether to keep it or remove it. Maintain counts for open parentheses and remaining removals. When adding characters to the current path, ensure validity rules: the number of closing parentheses never exceeds opening ones. If a parenthesis is removed, decrease the appropriate removal counter. Backtracking explores all valid constructions while pruning branches that would create invalid states. A set is often used to deduplicate results. Compared with BFS, DFS generates results by constructing valid strings directly instead of exploring all intermediate states. This technique demonstrates strong understanding of backtracking and recursion pruning strategies.

Recommended for interviews: BFS is usually the most intuitive explanation because it naturally guarantees the minimum removals. Many candidates start there to show correctness reasoning. DFS with backtracking is often considered the stronger solution once you compute the exact number of parentheses that must be removed. It reduces unnecessary states and demonstrates pruning, recursion control, and deeper algorithmic thinking. Interviewers typically expect one of these two strategies with correct duplicate handling and a clear validity check.

Approach 1: Breadth-First Search (BFS)

This approach uses a BFS technique. The idea is to start with the original string and try to remove each parenthesis at each level, generating a new state each time. We are looking for the shortest valid string, hence the BFS approach ensures that we explore the minimum removal solution first.

The critical parts of the approach are:

  • Use a queue to store intermediate states of string removal.
  • Use a set to keep track of visited states to avoid redundant work.
  • Level by level, try removing each parentheses '(' or ')' and check if the remaining string is valid.
  • Once a valid state is found, further remove operations are ceased at that level since BFS ensures minimum operations are performed.
from collections import deque

def removeInvalidParentheses(s):
    def isValid(string):
        balance = 0
        for char in string:
            if char == '(': balance += 1
            if char == ')': balance -= 1
            if balance < 0: return False
        return balance == 0
    
    queue = deque([s])
    visited = set([s])
    found = False
    valid_expressions = []

    while queue:
        expression = queue.popleft()
        
        if isValid(expression):
            found = True
            valid_expressions.append(expression)
        
        if found:
            continue
        
        for i in range(len(expression)):
            if expression[i] not in ('(', ')'):
                continue
            next_expression = expression[:i] + expression[i+1:]
            if next_expression not in visited:
                visited.add(next_expression)
                queue.append(next_expression)

    return valid_expressions
#include <iostream>
#include <queue>
#include <unordered_set>
#include <vector>
using namespace std;

bool isValid(const string &s) {
    int balance = 0;
    for (char c : s) {
        if (c == '(') balance++;
        if (c == ')') balance--;
        if (balance < 0) return false;
    }
    return balance == 0;
}

vector<string> removeInvalidParentheses(string s) {
    unordered_set<string> visited;
    queue<string> q;
    vector<string> result;
    q.push(s);
    visited.insert(s);
    bool found = false;
    
    while (!q.empty()) {
        string str = q.front(); q.pop();
        
        if (isValid(str)) {
            found = true;
            result.push_back(str);
        }

        if (found) continue;

        for (size_t i = 0; i < str.length(); ++i) {
            if (str[i] != '(' && str[i] != ')') continue;
            string next = str.substr(0, i) + str.substr(i + 1);
            if (!visited.count(next)) {
                visited.insert(next);
                q.push(next);
            }
        }
    }
    return result;
}

This Python function uses a queue to explore each possible state of the string. For each invalid state, we remove one parenthesis at each position and check the new state. A visited set is used to avoid processing the same string multiple times, ensuring more efficient performance.

Complexity

Time Complexity: O(2^n). For each character in the string, there are two choices: include it or not, hence exponential complexity. However, pruning the search space often reduces this in practical scenarios.

Space Complexity: O(n). Space is used to store the queue and the set of visited states.

Try this approach in the editor

Approach 2: Depth-First Search (DFS) with Backtracking

DFS with backtracking is a common technique in situations where all combinations must be explored. In this problem, we explore each possible configuration and backtrack when we identify that no valid state can follow the current configuration.

The primary characteristics of this approach are:

  • Recursively explore each character, either remove or keep it, leading to a valid configuration.
  • Ensure the counting of invalid parentheses removal is minimized using backtracking.
import java.util.HashSet;
import java.util.Set;

public class RemoveInvalidParentheses {

    public List<String> removeInvalidParentheses(String s) {
        Set<String> results = new HashSet<>();
        int[] minRemoved = {Integer.MAX_VALUE};
        
        int balance = 0, leftRem = 0, rightRem = 0;
        for (char c : s.toCharArray()) {
            if (c == '(') {
                leftRem++;
            } else if (c == ')') {
                if (leftRem == 0) rightRem++;
                else leftRem--;
            }
        }

        dfs(s, 0, 0, 0, leftRem, rightRem, new StringBuilder(), results, 0, minRemoved);

        return new ArrayList<>(results);
    }

    private void dfs(String s, int index, int leftCount, int rightCount, int leftRem, int rightRem, StringBuilder expression, Set<String> results, int removed, int[] minRemoved) {
        if (index == s.length()) {
            if (leftRem == 0 && rightRem == 0) {
                if (removed <= minRemoved[0]) {
                    if (removed < minRemoved[0]) {
                        results.clear();
                        minRemoved[0] = removed;
                    }
                    results.add(expression.toString());
                }
            }
            return;
        }

        char currentChar = s.charAt(index);
        int length = expression.length();

        if ((currentChar == '(' && leftRem > 0) || (currentChar == ')' && rightRem > 0)) {
            dfs(s, index + 1, leftCount, rightCount, leftRem - (currentChar == '(' ? 1 : 0), rightRem - (currentChar == ')' ? 1 : 0), expression, results, removed + 1, minRemoved);
        }

        expression.append(currentChar);

        if (currentChar != '(' && currentChar != ')') {
            dfs(s, index + 1, leftCount, rightCount, leftRem, rightRem, expression, results, removed, minRemoved);
        } else if (currentChar == '(') {
            dfs(s, index + 1, leftCount + 1, rightCount, leftRem, rightRem, expression, results, removed, minRemoved);
        } else if (rightCount < leftCount) {
            dfs(s, index + 1, leftCount, rightCount + 1, leftRem, rightRem, expression, results, removed, minRemoved);
        }

        expression.deleteCharAt(length);
    }
}
function removeInvalidParentheses(s) {
    const isValid = (str) => {
        let count = 0;
        for (let char of str) {
            if (char === '(') count++;
            if (char === ')') count--;
            if (count < 0) return false;
        }
        return count === 0;
    };

    let results = new Set();
    let minRemoved = Infinity;

    const dfs = (str, start, l, r, removed) => {
        if (removed > minRemoved) return;
        if (l === 0 && r === 0) {
            if (isValid(str)) {
                if (removed < minRemoved) {
                    results.clear();
                    minRemoved = removed;
                }
                results.add(str);
            }
            return;
        }

        for (let i = start; i < str.length; i++) {
            if (i > start && str[i] === str[i - 1]) continue; // Skip duplicate
            if (str[i] === '(' && l > 0) {
                dfs(str.slice(0, i) + str.slice(i + 1), i, l - 1, r, removed + 1);
            }
            if (str[i] === ')' && r > 0) {
                dfs(str.slice(0, i) + str.slice(i + 1), i, l, r - 1, removed + 1);
            }
        }
    };

    let leftRem = 0, rightRem = 0;
    for (let char of s) {
        if (char === '(') leftRem++;
        if (char === ')') {
            if (leftRem === 0) rightRem++;
            else leftRem--;
        }
    }

    dfs(s, 0, leftRem, rightRem, 0);
    return Array.from(results);
}

This Java implementation follows a recursive depth-first traversal with backtracking. It methodically explores each path, storing the minimum invalid removals using a recursive state parameter array with minimum removals.

Complexity

Time Complexity: O(2^n). Each character can be removed or preserved, leading to exponential growth. Dynamic pruning ensures efficiency.

Space Complexity: O(n). Recursive call stack depth up to n levels, with dynamic list to return results.

Try this approach in the editor

Approach 3: Default Approach

func removeInvalidParentheses(s string) []string {
	vis := map[string]bool{}
	l, r, n := 0, 0, len(s)
	for _, c := range s {
		if c == '(' {
			l++
		} else if c == ')' {
			if l > 0 {
				l--
			} else {
				r++
			}
		}
	}
	var dfs func(i, l, r, lcnt, rcnt int, t string)
	dfs = func(i, l, r, lcnt, rcnt int, t string) {
		if i == n {
			if l == 0 && r == 0 {
				vis[t] = true
			}
			return
		}
		if n-i < l+r || lcnt < rcnt {
			return
		}
		if s[i] == '(' && l > 0 {
			dfs(i+1, l-1, r, lcnt, rcnt, t)
		}
		if s[i] == ')' && r > 0 {
			dfs(i+1, l, r-1, lcnt, rcnt, t)
		}
		x, y := 0, 0
		if s[i] == '(' {
			x = 1
		} else if s[i] == ')' {
			y = 1
		}
		dfs(i+1, l, r, lcnt+x, rcnt+y, t+string(s[i]))
	}
	dfs(0, l, r, 0, 0, "")
	ans := make([]string, 0, len(vis))
	for v := range vis {
		ans = append(ans, v)
	}
	return ans
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Breadth-First Search (BFS)

Time Complexity: O(2^n). For each character in the string, there are two choices: include it or not, hence exponential complexity. However, pruning the search space often reduces this in practical scenarios.

Space Complexity: O(n). Space is used to store the queue and the set of visited states.

Depth-First Search (DFS) with Backtracking

Time Complexity: O(2^n). Each character can be removed or preserved, leading to exponential growth. Dynamic pruning ensures efficiency.

Space Complexity: O(n). Recursive call stack depth up to n levels, with dynamic list to return results.

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Breadth-First Search (BFS)O(2^n)O(2^n)Best when you want guaranteed minimum removals and a straightforward level-by-level search.
DFS with BacktrackingO(2^n)O(2^n)Preferred when pruning invalid states early and constructing valid strings directly.

Frequently asked questions

Is Remove Invalid Parentheses easy or hard?

Remove Invalid Parentheses is classified as a Hard problem because it combines exponential search with pruning and duplicate handling. Candidates must design a strategy that guarantees minimum removals while generating all valid outputs.

Remove Invalid Parentheses Python/Java solution

Python and C++ solutions commonly use BFS with a queue and visited set. Java and JavaScript implementations often demonstrate DFS with backtracking, tracking remaining removals and open parentheses counts to maintain validity.

How to solve Remove Invalid Parentheses in O(n)?

An O(n) solution does not exist because the problem requires generating all valid results after removing parentheses. In the worst case, exponentially many combinations must be explored. The optimal practical strategies are BFS or DFS with pruning, both with O(2^n) complexity.

What is the best approach for Remove Invalid Parentheses?

Breadth-First Search (BFS) is widely considered the most intuitive approach because it explores strings by number of removals. The first level that produces valid strings guarantees the minimum number of removals. Depth-First Search with backtracking is also popular because it prunes invalid states while constructing valid strings.

Is Remove Invalid Parentheses asked at Google/Amazon/Meta?

Remove Invalid Parentheses has appeared in interviews at large tech companies including Google, Meta, and Amazon. The problem tests search strategies, pruning techniques, and understanding of BFS versus DFS state exploration.

What data structure is used in Remove Invalid Parentheses?

Common implementations use a queue and hash set for BFS to track visited strings and avoid duplicates. DFS solutions rely on recursion, backtracking state variables, and sometimes a set to store unique results.

What is the time complexity of Remove Invalid Parentheses?

Both BFS and DFS with backtracking have worst-case time complexity of O(2^n). Each character can potentially be removed or kept, producing an exponential number of candidate strings. Space complexity is also O(2^n) due to storing generated states or recursion paths.

Comments

Now write it yourselfClose this page and solve Remove Invalid Parentheses in the editor, without looking.
Practise Remove Invalid Parentheses