要求:删除最少括号,返回所有可能结果
思路:显然要暴力回溯。首先确定最少删几个左右括号,然后遍历每个字符尝试删除即可。注意的是这里删除是跳过不选,也就是说实际上我们做的只是选取字符而非删除,选取右括号时必须左括号数大于才行。最后set去重。
class Solution {
public:
unordered_set<string> unique;
vector<string> removeInvalidParentheses(string s) {
int l = 0; // 左括号需要删除的数量;
int r = 0; // 右括号需要删除的数量;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
// 遇到左括号计数;如果有匹配的右括号,可以抵消;
// 抵消不了的都是我们需要删除的左括号
l++;
} else if (s[i] == ')') {
if (l == 0) // 左括号为0;此时遇到右括号一定是匹配不了的,需要删除的
r++;
else // 匹配掉一个左括号,相当于出栈
l--;
}
}
string t = "";
dfs(s, t, 0, l, r, 0, 0);
vector<string> ans;
for (auto s: unique)
ans.push_back(s);
return ans;
}
void dfs(string& s, string& t, int i, int l, int r, int lcnt, int rcnt) {
if (i == s.size()) {
if (l == 0 && r == 0) unique.insert(t);
return;
}
// 不选,但剩下需要删除的括号不能小于0
if (s[i] == '(' && l > 0)
dfs(s, t, i+1, l - 1, r, lcnt, rcnt);
if (s[i] == ')' && r > 0)
dfs(s, t, i+1, l , r - 1, lcnt, rcnt);
// 选;可能是括号,也可能是字母
t.push_back(s[i]);
if (s[i] != '(' && s[i] != ')') {
// 如果是字母,不用处理
dfs(s, t, i+1, l, r, lcnt, rcnt);
} else if (s[i] == '(') {
// 如果是左括号,我们更新左括号的数量
dfs(s, t, i+1, l, r, lcnt+1, rcnt);
} else if (rcnt < lcnt) {
// 避免出现 `)(` 这样的情况
dfs(s, t, i+1, l, r, lcnt, rcnt+1);
}
t.pop_back();
}
};