Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.
Note: The input string may contain letters other than the parentheses ( and ).
Example 1:
Input: “()())()”
Output: ["()()()", “(())()”]
Example 2:
Input: “(a)())()”
Output: ["(a)()()", “(a())()”]
Example 3:
Input: “)(”
Output: [""]
给出一个字符串,移除最小数量的括号,使得输入有效(即左括号和右括号匹配),要求输出所有有效的输出。
思路:
首先要判断括号是否匹配,即输入是否有效。
以前判断括号有效常用到Stack,这里模拟Stack,右括号出现时,左括号出栈,没有左括号时说明无效。即字符串没有结束时,右括号的数量要少于左括号,字符串结束时,左右括号数量相等。
public boolean isValid(String s) {
int count = 0;
//i < length(s): left count >= right count
//i = length(s): left count = right count
for(int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
count ++;
} else if (s.charAt(i) == ')') {
count --;
}
if (count < 0) {
return false;
}
}
return (count == 0);
}
因为要删除最小数量的括号,所以要统计出左括号要删掉多少个,右括号要删掉多少个。
要删除的左括号的数量可以用上面的思路,出现一个左括号+1,出现一个右括号-1,左括号的数量为0时如果出现右括号,说明需要删除的右括号+1。
for(int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
left ++;
} else if (s.charAt(i) == ')') {
if (left == 0) {
right ++;
} else {
left --;
}
}
}
知道了需要删除多少个左括号,多少个右括号,接下来就是遍历输入的字符串,删除掉这么多括号即可,删除掉之后要检测字符串是否有效,有效的话添加到输出的list中。
但是比如几个括号连续时,如 " ( ( ( ) ", 前3个左括号删除掉哪一个结果都是一样的,所以当出现连续相同括号时,只删除掉第一个。 删除掉一个后,以当前index为起始点,遍历剩下部分的substring,同时前面统计的要删除的左括号数量-1,进入下一轮递归,也就是DFS。
注意:
java中string不能直接操作,要用StringBuilder, 如果直接把StringBuilder做DFS参数,StringBuilder是Object型,DFS返回以后会是修改过的字符串,而不是传入DFS前的字符串,因此需要新建一个StringBuilder保存DFS处理前的字符串。
这里给DFS传入string型
public List<String> removeInvalidParentheses(String s) {
int left = 0;
int right = 0;
List<String> result = new ArrayList<>();
for(int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
left ++;
} else if (s.charAt(i) == ')') {
if (left == 0) {
right ++;
} else {
left --;
}
}
}
//StringBuilder sb = new StringBuilder(s);
dfs(s, 0, left, right, result);
return result;
}
public void dfs(String s, int start, int left, int right, List<String> result) {
if (left == 0 && right == 0) {
if(isValid(s)) {
result.add(s);
}
return;
}
for(int i = start; i < s.length(); i++) {
//有重复的括号出现时,只删除第一个,其余跳过
if (i > start && s.charAt(i) == s.charAt(i - 1)) {
continue;
}
if (s.charAt(i) == '(' || s.charAt(i) == ')') {
//string不能修改,建立StringBuilder
StringBuilder sb = new StringBuilder(s);
sb.deleteCharAt(i);
//delete ')' first
if (right > 0 && s.charAt(i) == ')') {
dfs(sb.toString(), i, left, right - 1, result);
}
if (left > 0 && s.charAt(i) == '(') {
dfs(sb.toString(), i, left - 1, right, result);
}
}
}
}
public boolean isValid(String s) {
int count = 0;
//i < length(s): left count >= right count
//i = length(s): left count = right count
for(int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
count ++;
} else if (s.charAt(i) == ')') {
count --;
}
if (count < 0) {
return false;
}
}
return (count == 0);
}