301. 删除无效的括号
Q:
删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。
说明: 输入可能包含了除 ( 和 ) 以外的字符。
示例 1:
输入: “()())()”
输出: ["()()()", “(())()”]
示例 2:
输入: “(a)())()”
输出: ["(a)()()", “(a())()”]
示例 3:
输入: “)(”
输出: [""]
A:
这题最主要是一开始要算出要删除的左括号和右括号的数量,以此作为目标去进行递归,不然情况是2的n次方。
dfs或bfs都可以,但由于对每次字符串的遍历中要保存剩余要删除的左右括号数量,dfs会显得方便一些,因为可以直接加在函数参数里。而bfs加参数不好加,要么定义个struct,或者多个queue同时push、pop。
注意有两个地方剪枝,大大减少了运算量。
1: 当前dfs函数遍历的字符串为s1,在索引i位置删除一个括号后得到s2,在dfs(s2)函数中从i开始遍历就可以了,前面的元素都已经在父函数dfs(s1)中遍历过了。
2: 当前遍历到i,若s[i-1]==s[i],则不必删除s[i]进入子层dfs,因为删除s[i]和删除s[i-1]得到的字符串是一样的。在前一个删除s[i-1]的dfs函数中考察过了,故可以直接跳过。但一定注意,当前遍历到i若有s[i]==s[i+1],不能向刚才那样跳过。这样如果有连续(((((这样的串,会连续跳到结尾而没有考察任何一个!之前可以跳是建立在已经考察过相同情况的子串的前提之下的!
class Solution {
public:
bool check(const string& s)
{
int cnt=0,siz=s.size();
for(int i=0;i<siz;++i)
{
if(s[i]!='(' and s[i]!=')')
{
continue;
}
if(s[i]=='(')
{
++cnt;
}
if(s[i]==')')
{
if(cnt>0)
{
--cnt;
}
else
{
return false;
}
}
}
return cnt==0;
}
vector<string> removeInvalidParentheses(string s)
{
int le=0,ri=0;
vector<string> res;
for(int i=0;i<s.length();++i)
{
if(s[i]=='(')
{
++le;
}
if(s[i]==')')
{
if(le>0)
{
--le; //前面有左括号则配对
}
else
{
++ri; //否则右括号多一个
}
}
}
//DFS
set<string> myset;
dfs(s,le,ri,0,myset);
for(auto x:myset)
{
res.push_back(x);
}
return res;
}
void dfs(string s,int left,int right,int limit,set<string>& res)
{
// cout<<s<<" "<<left<<" "<<right<<endl;
if(left==0 and right==0)
{
if(check(s))
{
res.insert(s);
}
return;
}
for(int i=limit;i<s.length();++i) //从limit开始遍历,省略不必要的遍历
{
if(i>limit and s[i]==s[i-1])
{
continue;
}
if(s[i]=='(' and left>0)
{
dfs(s.substr(0,i)+s.substr(i+1),left-1,right,i,res);
}
if(s[i]==')' and right>0)
{
dfs(s.substr(0,i)+s.substr(i+1),left,right-1,i,res);
}
}
}
};
进击的小🐴农