题目描述:
删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。
说明: 输入可能包含了除 ( 和 ) 以外的字符。
示例 1:
输入: “()())()”
输出: ["()()()", “(())()”]
示例 2:
输入: “(a)())()”
输出: ["(a)()()", “(a())()”]
示例 3:
输入: “)(”
输出: [""]
方法1:
参考代码
主要思路:
(1)先统计出要删除的左括号和右括号的数量;
(2)使用递归生成需要的字符串,具体看代码;
(3)为了去除重复的元素,使用unordered_set进行去重,最后将unordered_set转成vector返回;
class Solution {
public:
//递归
void dfs(string& s,unordered_set<string>& st,string path,int erase_l,int erase_r,int index,int diff){
if(index==s.size()){//在索引满足要求时
if(diff==0){//若已经加入到当前字符串的左右括号的数量满足要求,则是符合要求的字符串
st.insert(path);
}
return;
}
//若当前字符是左括号
if(s[index]=='('){
//将当前左括号加入到当前字符串中
dfs(s,st,path+s[index],erase_l,erase_r,index+1,diff+1);
if(erase_l>0){//若还能够删除左括号,则尝试跳过当前括号,既相当于删除当前左括号,继续递归
dfs(s,st,path,erase_l-1,erase_r,index+1,diff);
}
}
else if(s[index]==')'){//若当前字符是右括号
if(diff>0){//若当前字符串中左括号更多,说明可以将当前的右括号加入到当前字符串中
dfs(s,st,path+s[index],erase_l,erase_r,index+1,diff-1);
}
if(erase_r>0){//若还能够删除右括号,则尝试跳过右括号,既相当于删除右括号,继续递归
dfs(s,st,path,erase_l,erase_r-1,index+1,diff);
}
}
else{//若当期字符不是括号,则直接添加到当前字符串中
dfs(s,st,path+s[index],erase_l,erase_r,index+1,diff);
}
}
vector<string> removeInvalidParentheses(string s) {
//分别统计左右括号需要删除的数量
int erase_l=0;
int erase_r=0;
for(char&ch:s){
if(ch=='('){
++erase_l;//统计右括号的数量
}
else if(ch==')'){
if(erase_l==0){
++erase_r;//没有可匹配的左括号时,统计右括号的数量
}
else{
--erase_l;//在可以和右括号匹配时,减少左括号的数量
}
}
}
unordered_set<string> st;//用于去重字符串,并存储字符串
dfs(s,st,"",erase_l,erase_r,0,0);
return vector<string> (st.begin(),st.end());//返回vector
}
};
方法2:
主要思路:
(1)该方法是对方法1的优化,既直接在生成当前字符串时避免生成重复的字符串,不再使用unordered_set进行去重;
(2)主要是通过一次找出所有的连续的重复的括号的个数,进行递归;
class Solution {
public:
void dfs(string& s,vector<string>& res,string path,int erase_l,int erase_r,int index,int diff){
//终止条件,既遍历到了字符串的末尾
if(index==s.size()){
if(diff==0){//若条件满足,则将当前字符串压入到结果中
res.push_back(path);
}
return;
}
if(s[index]=='('){//若当前字符是左括号
//找出连续的左括号的范围的右边的索引
int k=index;
while(k<s.size()&&s[k]=='('){
++k;
}
//先假设删除该段的所有的左括号
erase_l-=k-index;
//该循环中,逐渐添加左括号,直到不需要删除左括号的情形
for(int i=k-index;i>=0;--i){
if(erase_l>=0){//说明此时是合理的删除范围,可以递归进行判断,注意索引的起始点一直是 k
dfs(s,res,path,erase_l,erase_r,k,diff);
}
//逐渐的添加左括号
path+='(';
++diff;
++erase_l;
}
}
else if(s[index]==')'){//当前的字符是右括号
//找出连续的右括号范围的右边的索引
int k=index;
while(k<s.size()&&s[k]==')'){
++k;
}
//先假设删除该段的所有的右括号
erase_r-=k-index;
//该循环中,逐渐的添加右括号,直到不需要删除右括号的情形
for(int i=k-index;i>=0;--i){
//若当前字符可删除,且是合理的字符串(合理是指当前字符串中左括号的数量是大于右括号的数量的),则进行递归调用
if(diff>=0&&erase_r>=0){
dfs(s,res,path,erase_l,erase_r,k,diff);
}
//添加右括号
path+=')';
--diff;
++erase_r;
}
}
else{//正常的将非括号的字符添加到字符串中
dfs(s,res,path+s[index],erase_l,erase_r,index+1,diff);
}
}
vector<string> removeInvalidParentheses(string s) {
//统计需要删除的左右括号的数量
int erase_l=0;
int erase_r=0;
for(char&ch:s){
if(ch=='('){
++erase_l;
}
else if(ch==')'){
if(erase_l==0){
++erase_r;
}
else{
--erase_l;
}
}
}
//直接存储字符串
vector<string> res;
dfs(s,res,"",erase_l,erase_r,0,0);
return res;
}
};