题目描述
删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。
说明: 输入可能包含了除 ( 和 ) 以外的字符。
示例 1:
输入: "()())()"
输出: ["()()()", "(())()"]
示例 2:
输入: "(a)())()"
输出: ["(a)()()", "(a())()"]
示例 3:
输入: ")("
输出: [""]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-invalid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
对每一个位置都有删除和不删除两个选项,可以暴力dfs,但是显然时间复杂度无法接受,是O(2^n)
分析得到最优解的路径,假设需要删除x个括号
第一次删除 某个位置 的括号,可能有多个位置
第二对第一次删除后的结果,再删除某个位置的括号
…
操作x次后,得到的结果集合就是答案
这样的操作树,刚好满足BFS的特征
- 使用哈希set来存储string类,作为每次的起始集合
- 遍历起始集合的所有string,对每个string,枚举删除的位置
- 得到下一层的结果集合,令起始集合 = 这个集合
- 一旦找到合法的括号,那么这一层所有的括号都合法
假设删除x次,那么我们就只用做x次删除,必定找得到答案,大大避免了不必要的搜索(比如删除x+1次以及他们之后的情况),这也是为何bfs在这个问题上优于dfs
而且使用集合的bfs可以有效避免重复的情况
代码
class Solution {
public:
// 判断合法
bool isValid(string& s)
{
deque<char> q;
for(int i=0; i<s.length(); i++)
{
if(s[i]!='(' && s[i]!=')') continue;
if(s[i]=='(') q.push_back(s[i]);
else if(s[i]==')' && !q.empty()) q.pop_back();
else if(s[i]==')' && q.empty()) return false;
}
return q.empty();
}
vector<string> removeInvalidParentheses(string s)
{
if(isValid(s)) return vector<string>{s};
unordered_set<string> now{s};
unordered_set<string> ans;
while(1)
{
unordered_set<string> next;
bool flag = false;
for(auto it=now.begin(); it!=now.end(); it++)
{
// 计算括号个数,如果为0说明访问到叶子节点,需要退出
int cnt = 0;
for(int i=0; i<(*it).length(); i++)
if((*it)[i]=='(' || (*it)[i]==')') cnt++;
if(cnt==0) {flag=true; break;}
// 枚举当前层每个节点不同位置,删除一个括号
for(int i=0; i<(*it).length(); i++)
{
string str = *it;
if(str[i]!='(' && str[i]!=')') continue;
str.erase(str.begin()+i);
next.insert(str);
if(isValid(str)) {flag=true; ans.insert(str);}
}
}
if(flag) break;
now = next;
}
return vector<string>(ans.begin(), ans.end());
}
};