有三个问题需要解决:
1.如何确定是有效状态?
2.如何保证我们获得的是最长的有效括号对(保证我们删除最小数量的无效括号)
3.如何保证结果中的字符串不重复
1.如果一个括号对序列,能保证每一个右括号的左面有大于等于右括号数量的左括号,并且整个括号对序列的数量相同
2.我们使用一个变量minDelete,记录我们删除括号数目的全局最小值,用curDelete记录我们当前结果删除的数量。
3.使用Set去存储结果
第一种方法:暴力
其中numOfLeft和numOfRight分别代表当前使用的左括号和右括号的个数
class Solution {
int minDelete = Integer.MAX_VALUE;
StringBuilder sb = new StringBuilder();
Set<String> res = new HashSet<>();
public List<String> removeInvalidParentheses(String s) {
helper(s,0,0,0,0);
return new ArrayList<>(res);
}
public void helper(String s, int index, int numOfLeft, int numOfRight, int curDelete){
if(index == s.length()){
if(numOfLeft == numOfRight){
if(curDelete < minDelete){
minDelete = curDelete;
res.clear();
res.add(sb.toString());
}
if(curDelete == minDelete){
res.add(sb.toString());
}
}
}else if(numOfRight > numOfLeft){
return;
}else{
char c = s.charAt(index);
if(c != '(' && c != ')'){
sb.append(c);
helper(s,index+1,numOfLeft,numOfRight,curDelete);
sb.deleteCharAt(sb.length()-1);
}else if(c == '('){
sb.append(c);
helper(s,index+1,numOfLeft+1,numOfRight,curDelete);
sb.deleteCharAt(sb.length()-1);
helper(s,index+1,numOfLeft,numOfRight,curDelete+1);
}else{
sb.append(c);
helper(s,index+1,numOfLeft,numOfRight+1,curDelete);
sb.deleteCharAt(sb.length()-1);
helper(s,index+1,numOfLeft,numOfRight,curDelete+1);
}
}
}
}
}
此方法十分的低效,因为我们尝试删除了每个可能的括号。其中包含了大量无用的遍历。事实上,我们是能知道最优结果的长度,这样我们的计算量就大大减少。根据我之前有效状态的定义,我们可以知道需要删除的左括号和右括号的数量。
如果我们遇到一个左括号,现在并不知道后面有没有右括号去匹配它。我们暂时把它记录成要删除的括号leftDelete+1,后面出现右括号,我们再调整。
如果我们遇到一个右括号,则有两种可能:
1)当leftDelete=0,也就是没有多余的可拿来匹配右括号的左括号,那么rightDelete+1
2)当leftDelete>0,这种情况下只需要leftDelete-1
这里的numOfLeft和numOfRight的定义和上面一样,为了保证有效性。
class Solution {
StringBuilder sb = new StringBuilder();
Set<String> res = new HashSet<>();
public List<String> removeInvalidParentheses(String s) {
int leftDelete = 0;
int rightDelete = 0;
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == '('){
leftDelete++;
}else if(s.charAt(i) == ')'){
rightDelete = leftDelete == 0 ? rightDelete+1 : rightDelete;
leftDelete = leftDelete > 0 ? leftDelete-1 : leftDelete;
}
}
helper(s, 0, 0, 0, leftDelete, rightDelete);
return new ArrayList<>(res);
}
public void helper(String s, int index, int numOfLeft, int numOfRight, int leftDelete, int rightDelete){
if(index == s.length()){
if(leftDelete==0 && rightDelete==0){
res.add(sb.toString());
}
}else if(numOfRight > numOfLeft){
return;
}else{
char c = s.charAt(index);
if((c == '(' && leftDelete>0) || (c == ')' && rightDelete>0)){
helper(s, index+1, numOfLeft,numOfRight,leftDelete-(c=='('?1:0),rightDelete-(c==')'?1:0));
}
sb.append(c);
if(c!='(' && c!=')'){
helper(s,index+1,numOfLeft,numOfRight,leftDelete,rightDelete);
}else if(c == '('){
helper(s,index+1,numOfLeft+1,numOfRight,leftDelete,rightDelete);
}else{
helper(s,index+1,numOfLeft,numOfRight+1,leftDelete,rightDelete);
}
sb.deleteCharAt(sb.length()-1);
}
}
}
先不添加,然后考虑添加的情况。