Facebook Pixel

301. Remove Invalid Parentheses

Problem Description

You are given a string s that contains parentheses (both opening '(' and closing ')') along with letters. The goal is to remove the minimum number of parentheses to make the string valid.

A string is considered valid when:

  • Every opening parenthesis '(' has a corresponding closing parenthesis ')'
  • Every closing parenthesis ')' has a corresponding opening parenthesis '(' that comes before it
  • The parentheses are properly balanced

The task requires you to:

  1. Find all possible valid strings that can be formed by removing the minimum number of parentheses
  2. Return all unique valid strings (no duplicates)
  3. The answer can be returned in any order

For example:

  • If s = "()())()", you need to remove 1 parenthesis. Possible answers: ["(())()","()()()"]
  • If s = "(a)())()", you need to remove 1 parenthesis. Possible answers: ["(a())()","(a)()()"]
  • If s = ")(", you need to remove 2 parentheses. Answer: [""]

The solution uses a depth-first search (DFS) approach where:

  1. First, it calculates how many left parentheses l and right parentheses r need to be removed
  2. Then it explores all possible ways to remove exactly l left parentheses and r right parentheses
  3. It tracks the count of left and right parentheses (lcnt, rcnt) to ensure validity during construction
  4. Uses a set to store unique valid strings and converts to a list before returning

Flowchart Walkthrough

First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:

Is it a graph?

  • Yes: We can model this as a graph problem where each state is a string, and edges represent removing one character. We're exploring all possible valid strings by removing parentheses.

Is it a tree?

  • No: The state space is not a tree structure. Multiple paths can lead to the same valid string (e.g., removing different parentheses might result in the same valid string).

Is the problem related to directed acyclic graphs?

  • No: This is not about directed acyclic graphs or dependencies between tasks.

Is the problem related to shortest paths?

  • Yes: We need to find valid strings with the MINIMUM number of removals. This is essentially finding the shortest path from the original string to any valid string, where each edge represents removing one character.

Is the graph Weighted?

  • No: Each removal operation has the same cost (removing one character). All edges have equal weight of 1.

BFS

  • Yes: Since we have an unweighted graph and need to find solutions with minimum removals (shortest path), BFS is the appropriate choice.

Conclusion: The flowchart suggests using BFS (Breadth-First Search) for this problem. BFS explores states level by level, ensuring we find all valid strings with the minimum number of removals before exploring strings with more removals. This guarantees we get the optimal solution (minimum removals) and can collect all possible valid strings at that minimum level.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is to think of this problem as exploring a state space where each state is a string, and we want to find all valid strings that are reachable with the minimum number of character removals.

Imagine starting with the original string and considering all possible ways to remove parentheses. Each removal creates a new string (a new state). If we remove one character, we get strings that are one step away. If we remove two characters, we get strings that are two steps away, and so on.

Since we want the minimum number of removals, we need to explore this state space level by level - first check all strings with 0 removals (just the original), then all strings with 1 removal, then 2 removals, and so forth. This is exactly what BFS does - it explores nodes level by level, guaranteeing we find the closest valid strings first.

However, the provided solution actually uses DFS with a clever optimization. Instead of blindly exploring all possibilities, it first calculates exactly how many left ( and right ) parentheses need to be removed. This is done by:

  1. Scanning the string once to identify unmatched parentheses
  2. For each (, increment a counter
  3. For each ), if there's a matching ( (counter > 0), decrement the counter; otherwise, it's an unmatched )
  4. After scanning, we know exactly l left and r right parentheses must be removed

With this knowledge, the DFS explores only combinations that remove exactly l left parentheses and r right parentheses. During the traversal, it maintains counts of left and right parentheses (lcnt, rcnt) to ensure we never have more ) than ( at any point (which would make the string invalid).

The pruning conditions n - i < l + r (not enough characters left to remove) and lcnt < rcnt (invalid state) help eliminate unnecessary branches early, making the search efficient despite using DFS instead of BFS.

Solution Approach

The implementation uses a DFS approach with intelligent pruning to find all valid strings with minimum removals.

Step 1: Calculate Required Removals

First, we determine exactly how many left and right parentheses need to be removed:

l = r = 0
for c in s:
    if c == '(':
        l += 1
    elif c == ')':
        if l:
            l -= 1  # Found a matching left parenthesis
        else:
            r += 1  # Unmatched right parenthesis
  • l: count of unmatched left parentheses to remove
  • r: count of unmatched right parentheses to remove

Step 2: DFS Exploration

The DFS function explores all ways to remove exactly l left and r right parentheses:

def dfs(i, l, r, lcnt, rcnt, t):

Parameters:

  • i: current index in the string
  • l, r: remaining left and right parentheses to remove
  • lcnt, rcnt: count of left and right parentheses in the current built string
  • t: the string being built

Step 3: Base Cases and Pruning

  1. Base case: When we've processed all characters (i == n):

    • If l == 0 and r == 0 (removed exact required amount), add to result set
  2. Pruning conditions:

    • n - i < l + r: Not enough characters left to remove required parentheses
    • lcnt < rcnt: Invalid state where we have more ) than ( so far

Step 4: Recursive Choices

At each position, we have two choices:

  1. Remove current character (if it's a parenthesis we need to remove):

    • If s[i] == '(' and l > 0: skip this ( and decrement l
    • If s[i] == ')' and r > 0: skip this ) and decrement r
  2. Keep current character:

    • Add to the built string t
    • Update lcnt or rcnt if it's a parenthesis
    • Continue to next position

Step 5: Collecting Results

  • Use a set to automatically handle duplicates (different removal combinations might produce the same valid string)
  • Convert to list before returning

The algorithm efficiently explores only the necessary branches by:

  • Pre-calculating exact removal requirements
  • Maintaining validity checks during construction
  • Pruning impossible branches early
  • Using a set to handle duplicate results automatically

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the example s = "()())()" step by step.

Step 1: Calculate Required Removals

We scan through the string to find unmatched parentheses:

  • Index 0: '(' → l = 1 (unmatched left)
  • Index 1: ')' → l = 0 (matched with previous '(')
  • Index 2: '(' → l = 1 (unmatched left)
  • Index 3: ')' → l = 0 (matched with previous '(')
  • Index 4: ')' → r = 1 (no unmatched '(' to pair with)
  • Index 5: '(' → l = 1 (unmatched left)
  • Index 6: ')' → l = 0 (matched with previous '(')

Final counts: l = 0, r = 1 (we need to remove 1 right parenthesis)

Step 2: DFS Exploration

Starting DFS with dfs(0, 0, 1, 0, 0, ""):

                         dfs(0,0,1,0,0,"")
                               |
                        i=0, s[0]='('
                               |
                    Keep '(' → dfs(1,0,1,1,0,"(")
                               |
                        i=1, s[1]=')'
                               |
                    Keep ')' → dfs(2,0,1,1,1,"()")
                               |
                        i=2, s[2]='('
                               |
                    Keep '(' → dfs(3,0,1,2,1,"()(")
                               |
                        i=3, s[3]=')'
                               |
                    Keep ')' → dfs(4,0,1,2,2,"()()")
                               |
                        i=4, s[4]=')'
                          /            \
                   Remove ')'        Keep ')'
                   (r=10)           (would make rcnt>lcnt, invalid)
                      |
               dfs(5,0,0,2,2,"()()")
                      |
               i=5, s[5]='('
                      |
            Keep '(' → dfs(6,0,0,3,2,"()()(")
                      |
               i=6, s[6]=')'
                      |
            Keep ')' → dfs(7,0,0,3,3,"()()()")
                      |
                i=7 (end), l=0, r=0
                      |
                Add "()()()" to result

The algorithm also explores another branch where it removes the ')' at index 4 after keeping '(' at index 5:

From dfs(4,0,1,2,2,"()()")
        |
   i=4, s[4]=')'
        |
   Keep ')' → dfs(5,0,1,2,3,"()())")
        |
   i=5, s[5]='('
        |
   Keep '(' → dfs(6,0,1,3,3,"()())("
        |
   i=6, s[6]=')'
      /    \
Remove ')'  Keep ')'
(r=10)     (continue)
    |           |
dfs(7,0,0,   dfs(7,0,1,
3,3,"()()(")  3,4,"()())()")
    |           |
Invalid      Invalid
(unbalanced) (r still > 0)

Wait, let me recalculate. Actually, when we keep ')' at index 4, we get rcnt = 3 and lcnt = 2, which violates lcnt < rcnt, so this branch is pruned.

Let me show the correct alternative path that leads to "(())()"

Starting from the beginning, but this time:
- Keep first 3 characters: "()(", lcnt=2, rcnt=1
- Keep ')' at index 3: "()()", lcnt=2, rcnt=2
- Remove ')' at index 4: still "()()", l=0, r=0
- Keep '(' at index 5: "()()(" lcnt=3, rcnt=2
- Keep ')' at index 6: "()()()" lcnt=3, rcnt=3
Result: "()()()"

Alternative path:
- Keep '(' at index 0: "(", lcnt=1, rcnt=0
- Keep ')' at index 1: "()", lcnt=1, rcnt=1
- Remove '(' at index 2: still "()", l=0, r=1
- Keep ')' at index 3: "())", lcnt=1, rcnt=2 → INVALID (rcnt > lcnt)

Another alternative:
- Keep '(' at index 0: "(", lcnt=1, rcnt=0
- Remove ')' at index 1: still "(", l=0, r=0
- Keep '(' at index 2: "((", lcnt=2, rcnt=0
- Keep ')' at index 3: "(()", lcnt=2, rcnt=1
- Keep ')' at index 4: "(())", lcnt=2, rcnt=2
- Keep '(' at index 5: "(())(" lcnt=3, rcnt=2
- Keep ')' at index 6: "(())()", lcnt=3, rcnt=3
Result: "(())()"

Step 3: Final Results

The algorithm finds two valid strings with exactly 1 removal:

  • "()()()" - removed the ')' at index 4
  • "(())()" - removed the ')' at index 1

These are collected in a set (avoiding duplicates) and returned as ["()()()","(())()"].

Solution Implementation

1class Solution:
2    def removeInvalidParentheses(self, s: str) -> List[str]:
3        def dfs(index: int, left_to_remove: int, right_to_remove: int, 
4                left_count: int, right_count: int, current_string: str) -> None:
5            """
6            Recursively explore all possible ways to remove invalid parentheses.
7          
8            Args:
9                index: Current position in the original string
10                left_to_remove: Number of '(' that still need to be removed
11                right_to_remove: Number of ')' that still need to be removed
12                left_count: Count of '(' in the current valid string being built
13                right_count: Count of ')' in the current valid string being built
14                current_string: The string being constructed
15            """
16            # Base case: reached end of string
17            if index == string_length:
18                # If all invalid parentheses have been removed, add to result
19                if left_to_remove == 0 and right_to_remove == 0:
20                    valid_results.add(current_string)
21                return
22          
23            # Pruning conditions:
24            # 1. Not enough characters left to remove required parentheses
25            # 2. More closing than opening parentheses (invalid state)
26            if string_length - index < left_to_remove + right_to_remove or left_count < right_count:
27                return
28          
29            # Option 1: Remove current '(' if it needs to be removed
30            if s[index] == '(' and left_to_remove > 0:
31                dfs(index + 1, left_to_remove - 1, right_to_remove, 
32                    left_count, right_count, current_string)
33          
34            # Option 2: Remove current ')' if it needs to be removed
35            elif s[index] == ')' and right_to_remove > 0:
36                dfs(index + 1, left_to_remove, right_to_remove - 1, 
37                    left_count, right_count, current_string)
38          
39            # Option 3: Keep current character (always explore this option)
40            # Update counts if the character is a parenthesis
41            new_left_count = left_count + (1 if s[index] == '(' else 0)
42            new_right_count = right_count + (1 if s[index] == ')' else 0)
43            dfs(index + 1, left_to_remove, right_to_remove, 
44                new_left_count, new_right_count, current_string + s[index])
45      
46        # Step 1: Calculate how many left and right parentheses need to be removed
47        left_to_remove = 0
48        right_to_remove = 0
49      
50        for char in s:
51            if char == '(':
52                left_to_remove += 1
53            elif char == ')':
54                if left_to_remove > 0:
55                    # This ')' can be paired with a previous '('
56                    left_to_remove -= 1
57                else:
58                    # This ')' has no matching '(', needs to be removed
59                    right_to_remove += 1
60      
61        # Initialize result set (using set to avoid duplicates)
62        valid_results = set()
63        string_length = len(s)
64      
65        # Start DFS exploration
66        dfs(0, left_to_remove, right_to_remove, 0, 0, '')
67      
68        # Convert set to list for return
69        return list(valid_results)
70
1class Solution {
2    // Instance variables to avoid passing multiple parameters
3    private String inputString;
4    private int stringLength;
5    private Set<String> validResults = new HashSet<>();
6
7    /**
8     * Remove the minimum number of invalid parentheses to make the input string valid.
9     * Returns all possible valid strings.
10     * 
11     * @param s the input string containing parentheses and other characters
12     * @return list of all valid strings after removing minimum invalid parentheses
13     */
14    public List<String> removeInvalidParentheses(String s) {
15        this.inputString = s;
16        this.stringLength = s.length();
17      
18        // Calculate minimum number of left and right parentheses to remove
19        int leftToRemove = 0;
20        int rightToRemove = 0;
21      
22        // First pass: count unmatched parentheses
23        for (char character : s.toCharArray()) {
24            if (character == '(') {
25                leftToRemove++;
26            } else if (character == ')') {
27                if (leftToRemove > 0) {
28                    // Found a matching left parenthesis
29                    leftToRemove--;
30                } else {
31                    // No matching left parenthesis, need to remove this right one
32                    rightToRemove++;
33                }
34            }
35        }
36      
37        // Start DFS to find all valid combinations
38        dfs(0, leftToRemove, rightToRemove, 0, 0, "");
39      
40        return new ArrayList<>(validResults);
41    }
42
43    /**
44     * Depth-first search to explore all possible ways to remove invalid parentheses.
45     * 
46     * @param index current position in the input string
47     * @param leftToRemove number of left parentheses still need to be removed
48     * @param rightToRemove number of right parentheses still need to be removed
49     * @param leftCount current count of left parentheses in the built string
50     * @param rightCount current count of right parentheses in the built string
51     * @param currentString the string being built
52     */
53    private void dfs(int index, int leftToRemove, int rightToRemove, 
54                     int leftCount, int rightCount, String currentString) {
55        // Base case: reached end of string
56        if (index == stringLength) {
57            // Check if we've removed all required parentheses
58            if (leftToRemove == 0 && rightToRemove == 0) {
59                validResults.add(currentString);
60            }
61            return;
62        }
63      
64        // Pruning conditions:
65        // 1. Not enough characters left to remove required parentheses
66        // 2. Right parentheses count exceeds left (invalid state)
67        if (stringLength - index < leftToRemove + rightToRemove || leftCount < rightCount) {
68            return;
69        }
70      
71        char currentChar = inputString.charAt(index);
72      
73        // Option 1: Remove current character if it's a parenthesis we need to remove
74        if (currentChar == '(' && leftToRemove > 0) {
75            // Remove this left parenthesis
76            dfs(index + 1, leftToRemove - 1, rightToRemove, leftCount, rightCount, currentString);
77        }
78        if (currentChar == ')' && rightToRemove > 0) {
79            // Remove this right parenthesis
80            dfs(index + 1, leftToRemove, rightToRemove - 1, leftCount, rightCount, currentString);
81        }
82      
83        // Option 2: Keep current character
84        // Update counts only if current character is a parenthesis
85        int leftIncrement = (currentChar == '(') ? 1 : 0;
86        int rightIncrement = (currentChar == ')') ? 1 : 0;
87      
88        dfs(index + 1, leftToRemove, rightToRemove, 
89            leftCount + leftIncrement, rightCount + rightIncrement, 
90            currentString + currentChar);
91    }
92}
93
1class Solution {
2public:
3    vector<string> removeInvalidParentheses(string s) {
4        unordered_set<string> result;  // Store unique valid results
5        int leftToRemove = 0;          // Count of '(' to remove
6        int rightToRemove = 0;         // Count of ')' to remove
7        int n = s.size();
8      
9        // First pass: calculate minimum number of parentheses to remove
10        for (char& ch : s) {
11            if (ch == '(') {
12                leftToRemove++;
13            } else if (ch == ')') {
14                if (leftToRemove > 0) {
15                    leftToRemove--;  // Found matching '(' for this ')'
16                } else {
17                    rightToRemove++;  // Extra ')' that needs to be removed
18                }
19            }
20        }
21      
22        // DFS function to explore all possible valid combinations
23        function<void(int, int, int, int, int, string)> dfs;
24        dfs = [&](int index, int leftRem, int rightRem, int leftCount, int rightCount, string current) {
25            // Base case: reached end of string
26            if (index == n) {
27                // Check if we've removed all invalid parentheses
28                if (leftRem == 0 && rightRem == 0) {
29                    result.insert(current);
30                }
31                return;
32            }
33          
34            // Pruning conditions:
35            // 1. Not enough characters left to remove required parentheses
36            // 2. More ')' than '(' at any point (invalid state)
37            if (n - index < leftRem + rightRem || leftCount < rightCount) {
38                return;
39            }
40          
41            // Option 1: Remove current '(' if we still need to remove left parentheses
42            if (s[index] == '(' && leftRem > 0) {
43                dfs(index + 1, leftRem - 1, rightRem, leftCount, rightCount, current);
44            }
45          
46            // Option 2: Remove current ')' if we still need to remove right parentheses
47            if (s[index] == ')' && rightRem > 0) {
48                dfs(index + 1, leftRem, rightRem - 1, leftCount, rightCount, current);
49            }
50          
51            // Option 3: Keep current character
52            int addLeft = (s[index] == '(') ? 1 : 0;
53            int addRight = (s[index] == ')') ? 1 : 0;
54            dfs(index + 1, leftRem, rightRem, leftCount + addLeft, rightCount + addRight, current + s[index]);
55        };
56      
57        // Start DFS from index 0
58        dfs(0, leftToRemove, rightToRemove, 0, 0, "");
59      
60        // Convert set to vector and return
61        return vector<string>(result.begin(), result.end());
62    }
63};
64
1function removeInvalidParentheses(s: string): string[] {
2    const result: Set<string> = new Set();  // Store unique valid results
3    let leftToRemove = 0;                   // Count of '(' to remove
4    let rightToRemove = 0;                  // Count of ')' to remove
5    const n = s.length;
6  
7    // First pass: calculate minimum number of parentheses to remove
8    for (const char of s) {
9        if (char === '(') {
10            leftToRemove++;
11        } else if (char === ')') {
12            if (leftToRemove > 0) {
13                leftToRemove--;      // Found matching '(' for this ')'
14            } else {
15                rightToRemove++;     // Extra ')' that needs to be removed
16            }
17        }
18    }
19  
20    // DFS function to explore all possible valid combinations
21    const dfs = (
22        index: number,           // Current position in string
23        leftRem: number,         // Remaining '(' to remove
24        rightRem: number,        // Remaining ')' to remove
25        leftCount: number,       // Count of '(' in current string
26        rightCount: number,      // Count of ')' in current string
27        current: string          // Current string being built
28    ): void => {
29        // Base case: reached end of string
30        if (index === n) {
31            // Check if we've removed all invalid parentheses
32            if (leftRem === 0 && rightRem === 0) {
33                result.add(current);
34            }
35            return;
36        }
37      
38        // Pruning conditions:
39        // 1. Not enough characters left to remove required parentheses
40        // 2. More ')' than '(' at any point (invalid state)
41        if (n - index < leftRem + rightRem || leftCount < rightCount) {
42            return;
43        }
44      
45        // Option 1: Remove current '(' if we still need to remove left parentheses
46        if (s[index] === '(' && leftRem > 0) {
47            dfs(index + 1, leftRem - 1, rightRem, leftCount, rightCount, current);
48        }
49      
50        // Option 2: Remove current ')' if we still need to remove right parentheses
51        if (s[index] === ')' && rightRem > 0) {
52            dfs(index + 1, leftRem, rightRem - 1, leftCount, rightCount, current);
53        }
54      
55        // Option 3: Keep current character
56        const addLeft = s[index] === '(' ? 1 : 0;
57        const addRight = s[index] === ')' ? 1 : 0;
58        dfs(index + 1, leftRem, rightRem, leftCount + addLeft, rightCount + addRight, current + s[index]);
59    };
60  
61    // Start DFS from index 0
62    dfs(0, leftToRemove, rightToRemove, 0, 0, "");
63  
64    // Convert set to array and return
65    return Array.from(result);
66}
67

Time and Space Complexity

Time Complexity: O(2^n)

The algorithm uses a DFS approach where at each position, we have up to 2 choices:

  • Skip the current character (when it's a parenthesis that needs to be removed)
  • Include the current character

In the worst case, we explore all possible subsequences of the string. Although there are pruning conditions (n - i < l + r and lcnt < rcnt) that help reduce the search space, the worst-case scenario still requires exploring an exponential number of possibilities. Each branch of the recursion tree can split into at most 2 branches, and the maximum depth is n, resulting in O(2^n) time complexity.

Space Complexity: O(n)

The space complexity consists of:

  • Recursion stack: The maximum depth of recursion is n (the length of the string), contributing O(n) to space complexity
  • String building: The parameter t in each recursive call can be at most length n, contributing O(n)
  • Result storage: The ans set stores valid strings. In the worst case, there could be multiple valid results, but each result string has length at most n. The number of valid results is typically much smaller than 2^n due to the constraints of valid parentheses
  • Variables: The variables l, r, lcnt, rcnt use O(1) space

The dominant factor is the recursion stack depth and the string building during recursion, giving us an overall space complexity of O(n).

Common Pitfalls

1. Incorrect Handling of Multiple Removal Options

Pitfall: A common mistake is using elif for the second removal option, which prevents exploring both removal possibilities when we can remove either a '(' or ')'.

Incorrect Code:

# Option 1: Remove current '(' if it needs to be removed
if s[index] == '(' and left_to_remove > 0:
    dfs(index + 1, left_to_remove - 1, right_to_remove, 
        left_count, right_count, current_string)

# WRONG: Using elif here!
elif s[index] == ')' and right_to_remove > 0:
    dfs(index + 1, left_to_remove, right_to_remove - 1, 
        left_count, right_count, current_string)

Why it's wrong: When we encounter a parenthesis that can be removed, we should explore BOTH possibilities: removing it AND keeping it. Using elif creates an exclusive choice that misses valid solutions.

Correct Approach:

# Option 1: Remove current '(' if it needs to be removed
if s[index] == '(' and left_to_remove > 0:
    dfs(index + 1, left_to_remove - 1, right_to_remove, 
        left_count, right_count, current_string)

# Option 2: Remove current ')' if it needs to be removed (separate if, not elif!)
if s[index] == ')' and right_to_remove > 0:
    dfs(index + 1, left_to_remove, right_to_remove - 1, 
        left_count, right_count, current_string)

# Option 3: Always try keeping the current character
new_left_count = left_count + (1 if s[index] == '(' else 0)
new_right_count = right_count + (1 if s[index] == ')' else 0)
dfs(index + 1, left_to_remove, right_to_remove, 
    new_left_count, new_right_count, current_string + s[index])

2. Forgetting Early Termination Check

Pitfall: Not checking if right_count > left_count during DFS traversal, which leads to exploring invalid branches unnecessarily.

Incorrect Code:

def dfs(index, left_to_remove, right_to_remove, left_count, right_count, current_string):
    if index == string_length:
        if left_to_remove == 0 and right_to_remove == 0:
            valid_results.add(current_string)
        return
  
    # Missing the validity check!
    if string_length - index < left_to_remove + right_to_remove:
        return

Correct Code:

def dfs(index, left_to_remove, right_to_remove, left_count, right_count, current_string):
    if index == string_length:
        if left_to_remove == 0 and right_to_remove == 0:
            valid_results.add(current_string)
        return
  
    # Include both pruning conditions
    if string_length - index < left_to_remove + right_to_remove or left_count < right_count:
        return

3. Using List Instead of Set for Results

Pitfall: Using a list to store results and trying to manually check for duplicates, which is inefficient and error-prone.

Incorrect Approach:

valid_results = []  # Using list

def dfs(...):
    if index == string_length:
        if left_to_remove == 0 and right_to_remove == 0:
            if current_string not in valid_results:  # O(n) check each time!
                valid_results.append(current_string)
        return

Correct Approach:

valid_results = set()  # Using set for automatic deduplication

def dfs(...):
    if index == string_length:
        if left_to_remove == 0 and right_to_remove == 0:
            valid_results.add(current_string)  # O(1) add with automatic dedup
        return

# Convert to list only at the end
return list(valid_results)

4. Incorrect Initial Count Calculation

Pitfall: Not properly tracking which parentheses can be paired during the initial scan.

Incorrect Code:

# Simply counting all parentheses
left_to_remove = s.count('(')
right_to_remove = s.count(')')

Correct Code:

left_to_remove = 0
right_to_remove = 0

for char in s:
    if char == '(':
        left_to_remove += 1
    elif char == ')':
        if left_to_remove > 0:
            left_to_remove -= 1  # This ')' pairs with a previous '('
        else:
            right_to_remove += 1  # This ')' has no match, must be removed
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which type of traversal does breadth first search do?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More