题干
删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。
说明: 输入可能包含了除 ( 和 ) 以外的字符。
示例 1:
输入: "()())()"
输出: ["()()()", "(())()"]
示例 2:
输入: "(a)())()"
输出: ["(a)()()", "(a())()"]
示例 3:
输入: ")("
输出: [""]
想法
回溯法:
用left,right来存已经遇到的( )数量
leftrem rightrem,用来存储应该删除的数量
递归完成条件:所有字符已经遍历,且左右需要删除都为0
递归:
1)如果当前字符是左括号,如果需要删除的左括号个数leftRem大于0,可以考虑忽略该左括号。否则,把c加上
(2)如果当前字符是右括号,如果需要删除的右括号个数rightRem大于0,可以考虑忽略该右括号。当然,还有一种情形——当左括号个数leftCount大于右括号个数rightCount时,不忽略该右括号。
(3)如果当前字符既不是左括号也不是右括号,直接将该字符加进结果即可。
Java代码
class Solution {
private Set<String> set;//存结果
private String input;
public List<String> removeInvalidParentheses(String s) {
input=s;
set=new HashSet<>();
int left=0,right=0;
//遍历记录左右括号数
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(c=='('){
left++;
}
else if(c==')'){
if(left==0){
right++;
}
else{
left--;
}
}
}
helper(0, "", 0, 0, left, right);//递归
return new ArrayList<>(set);
}
private void helper(int index, String valid, int leftCount, int rightCount, int leftRem, int rightRem) {
if(index==input.length()){
if(leftRem==0&&rightRem==0){//递归出口条件
set.add(valid);
}
return ;
}
char c=input.charAt(index);
if (c == '(') {
if (leftRem > 0) {
//左括号且左括号待删除,则删除,跳过它
helper(index + 1, valid, leftCount, rightCount, leftRem - 1, rightRem);
}//否则,加进去
helper(index + 1, valid + c, leftCount + 1, rightCount, leftRem, rightRem);
} else if (c == ')') {
if (rightRem > 0) {//右括号且需要删除跳过
helper(index + 1, valid, leftCount, rightCount, leftRem, rightRem - 1);
}
if (rightCount < leftCount) {//右括号且右括号更多
helper(index + 1, valid + c, leftCount, rightCount + 1, leftRem, rightRem);
}
} else {//否则,加
helper(index + 1, valid + c, leftCount, rightCount, leftRem, rightRem);
}
}
}
另一个很巧妙地思路
reverse很厉害,参考
[传送门]即可(https://blog.youkuaiyun.com/u010900754/article/details/56279595)