好生气啊
题目
https://leetcode-cn.com/problems/remove-invalid-parentheses/
分析
一、找出左括号和右括号放错的数目。
1.我们从左边开始,一次处理一个括号的表达式。
2.假设我们遇到一个左括号,即 ( ,它可能会导致或可能不会导致一个无效的表达式,因为表达式的其余部分的某个地方可能有一个匹配的右括号。这里,我们只需增加计数器来跟踪左括号的出现次数。left++。
3.如果我们遇到一个右括号,这有两种情况:
3.1 这个右括号没有匹配的左括号,该表达式是无效的。当 left == 0 时,即没有不匹配的左括号可用时,增加另一个计数器叫 right++ 来表示放错了位置的右括号。
3.2 有一些未匹配的左括号来匹配这个右括号。即,当 left > 0 时。在这种情况下,我们只需减小left 计数器,即 left - -。
4.继续处理字符串,直到处理完所有括号。
5.最后,左括号和右括号的值分别表示不匹配 ( 和 ) 括号的数目。
二、回溯
@param ss 字符串对应的字符数组
@param sb 储存当前处理过且未去除字符的字符串
@param index 当前处理的字符位置
@param open 当前sb中储存的左括号数
@param close 当前sb中储存的右括号数
@param openRem 当前需要去除的左括号数
@param closeRem 当前需要去除的右括号数
1.已经处理完整个长度。如果左右多余扩号都已删除完毕,添加进结果集。
2.当前位置是左括号,删除,回溯下一位;当前位置是右括号,删除,回溯下一位。
3.不去掉当前位,将当前位加入当前字符串。
4.当前位置不为括号,则直接处理下一个字符
5.当前位置为左括号,增加左括号计数,处理下一个字符。
6.当前位置为右括号,且当前左括号计数大于右括号计数,则增加右括号计数,处理下一个字符
最后,从字符串去除当前位,以便回溯。
复杂度
时间复杂度:我们所执行的优化只是一种更好的修剪形式。在最坏的情况下,我们可以丢弃所有字符,因为所有字符都放错了位置。
在最坏的情况下,每个括号中仍然有两个选项,即是删除还是考虑它。考虑到表达式有 N 括号,时间复杂性将为 O(2^n)。
空间复杂度:O(N)。 在到达基本情况之前,我们必须达到 N的最大递归深度。注意,我们不考虑存储有效表达式所需的空间。只计算中间过程空间。
代码
class Solution {
private Set<String> set = new HashSet<>();
public List<String> removeInvalidParentheses(String s) {
if(s==null){
ArrayList<String> l=new ArrayList<>();
l.add("");
return l;
}
char[] ss=s.toCharArray();
int leftcount=0;
int rightcount=0;
for(int i=0;i<ss.length;i++){
if(ss[i]=='(')
leftcount++;
else if(ss[i]==')'){
if(leftcount>0)
leftcount--;
else
rightcount++;
}
}
dfs(ss,new StringBuilder(),0,0,0,leftcount,rightcount);
return new ArrayList(set);
}
public void dfs(char[] ss,StringBuilder sb,int index,int open,int close,int openr,int closer){
//1.已过最后一位
if(index==ss.length){
//1.1 已删除全部多余扩号
if(openr==0&&closer==0){
set.add(sb.toString());
return;
}
//1.2 未删除全部多余扩号
return;
}
//2.去掉当前位
//2.1 当前位(
if(ss[index]=='('&&openr>0){
dfs(ss,sb,index+1,open,close,openr-1,closer);
}
//2.2 当前位)
if(ss[index]==')'&&closer>0){
dfs(ss,sb,index+1,open,close,openr,closer-1);
}
//3.不去掉当前位
sb.append(ss[index]);
//3.1 当前位(
if(ss[index]=='('){
dfs(ss,sb,index+1,open+1,close,openr,closer);
}
//3.2 当前位),且左括号计数大于右括号
else if(ss[index]==')'&&open>close){
dfs(ss,sb,index+1,open,close+1,openr,closer);
}
//3.2 当前位不是扩号
else if(ss[index]!='('&&ss[index]!=')'){
dfs(ss,sb,index+1,open,close,openr,closer);
}
//回溯
sb.deleteCharAt(sb.length()-1);
}
}