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 ')'
.20
parentheses in s
.This problem asks to remove the minimum number of invalid parentheses from a given string to make it valid, and return all unique valid strings. The solution employs a Depth-First Search (DFS) or equivalently, a Breadth-First Search (BFS) approach. The core idea is to systematically explore possible removals of parentheses while keeping track of the balance of opening and closing parentheses.
Approach:
Count Invalid Parentheses: First, we count the number of extra opening and closing parentheses. We iterate through the input string s
. For every opening parenthesis, we increment a counter l
. For every closing parenthesis, we decrement l
if l > 0
(meaning there's a matching opening parenthesis). Otherwise, we increment a counter r
to track extra closing parentheses.
Depth-First Search (DFS) / Backtracking: The DFS function explores all possible combinations of removing parentheses. It takes the following parameters:
i
: The current index in the string.l
: The number of extra opening parentheses to be removed.r
: The number of extra closing parentheses to be removed.lcnt
: The current count of opening parentheses.rcnt
: The current count of closing parentheses.t
: The current string being built.Base Case: If i
reaches the end of the string, and both l
and r
are 0 (meaning all extra parentheses have been removed), then the current string t
is a valid string, and it's added to the ans
set (to ensure uniqueness).
Pruning: We have several pruning conditions:
n - i < l + r
: If the remaining characters are fewer than the number of parentheses to remove, we can't possibly find a valid string.lcnt < rcnt
: If the count of closing parentheses exceeds the count of opening parentheses, the string is invalid. We should backtrack.Recursive Steps: For each character c
at index i
:
c
is an opening parenthesis and l > 0
, we recursively call dfs
after removing it (l - 1
).c
is a closing parenthesis and r > 0
, we recursively call dfs
after removing it (r - 1
).dfs
without removing the current character, incrementing lcnt
or rcnt
accordingly.Return Result: Finally, we convert the ans
set (which stores unique valid strings) into a list and return it.
Time Complexity Analysis:
The time complexity is difficult to express precisely because it depends on the structure of the input string. In the worst-case scenario, the algorithm explores a significant portion of the search space, which is exponential in the number of parentheses. Let's denote the number of parentheses as p
. The complexity can be approximated as O(2p * n), where n
is the length of the input string. The exponential part comes from the branching in the DFS, while the linear factor n
accounts for the string operations.
Space Complexity Analysis:
The space complexity is dominated by the recursion stack in the DFS and the ans
set to store the unique valid strings. In the worst case, the depth of the recursion stack could be proportional to the number of parentheses p
, and the size of the ans
set can be exponential in the number of parentheses. Therefore, the space complexity can be approximated as O(2p + p), where p is the number of parentheses in the input string.
Code in Different Languages:
The code examples provided in Python, Java, C++, and Go all implement the same algorithm with minor variations in syntax and data structures. They all follow the steps described above to find and return all possible valid strings after removing the minimum number of invalid parentheses. The use of a set
(HashSet
in Java, unordered_set
in C++, map
in Go) is crucial for efficiently storing and retrieving unique valid strings.