/**
* 1249. Minimum Remove to Make Valid Parentheses
* Given a string s of ‘(‘ , ‘)’ and lowercase English characters.
* Your task is to remove the minimum number of parentheses ( ‘(‘ or ‘)’, in any positions )
* so that the resulting parentheses string is valid and return any valid string.
* Formally, a parentheses string is valid if and only if:
* It is the empty string, contains only lowercase characters, or
* It can be written as AB (A concatenated with B), where A and B are valid strings, or
* It can be written as (A), where A is a valid string.
* Example 1:
* Input: s = “lee(t(c)o)de)”
* Output: “lee(t(c)o)de”
* Explanation: “lee(t(co)de)” , “lee(t(c)ode)” would also be accepted.
*/
See solution on github here: https://github.com/zcoderz/leetcode/blob/main/src/main/java/frequent/medium/ParenthesisRemove.java
This is a very common interview question. I have included the solution below as it’s a very elegant way to solve this problem.
Algorithm is:
- Create a stack for open parenthesis and a list for unmatched closed parenthesis
- Iterate through characters in the string left to right
- When an open parenthesis is found add it to stack
- When a closed parenthesis is found
- If open stack is not empty, pop one from open stack
- Otherwise add closed index to the closed list
- Add any remaining items in open stack to the closed list
- Sort the items in closed list in reverse order (highest index first)
- Copy string to string builder so you can adjust it efficiently
- Iterate through the closed list which now has highest indexes first
- Delete characters from the string builder (deleting highest first so that order of items in the string builder stays consistent).
Here is the code:
public String minRemoveToMakeValid(String s) {
Stack<Integer> stackOpen = new Stack<>();
List<Integer> close = new ArrayList<>();
//do regular stack processing
for (int i =0; i < s.length(); i++) {
if(s.charAt(i)=='(') {
stackOpen.push(i);
} else if (s.charAt(i) == ')') {
if (stackOpen.isEmpty()) {
close.add(i); //these need to be removed so add them to a separate collection
} else {
stackOpen.pop();
}
}
}
//merge open with close in same collection
while (!stackOpen.isEmpty()) {
close.add(stackOpen.pop());
}
//sort reverse , delete chars from end to beginning so that your indexes stay consistent
Collections.sort(close, (a, b) -> b - a);
//java string are immutable, so copy them to string builder and then modify
StringBuilder builder = new StringBuilder(s);
for (Integer i : close) {
builder.deleteCharAt(i);
}
return builder.toString();
}