原题链接:力扣
题目描述:
给你一个由若干括号和字母组成的字符串 s
,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。(困难)
背景知识
有效的「括号」:题目输入的字符串由一系列「左括号」和「右括号」组成,但是有一些额外的括号,使得括号不能正确配对。对于括号配对规则如果还不太清楚的读者,可以先完成问题「20. 有效的括号」。
可以一次遍历计算出多余的「左括号」和「右括号」:
根据括号匹配规则和根据求解「22. 括号生成」的经验,我们知道:如果当前遍历到的「左括号」的数目严格小于「右括号」的数目则表达式无效。因此,我们可以遍历一次输入字符串,统计「左括号」和「右括号」出现的次数。
当遍历到「左括号」的时候:
「左括号」数量加 11。
当遍历到「右括号」的时候:
如果此时「左括号」的数量不为 00,因为「右括号」可以与之前遍历到的「左括号」匹配,此时「左括号」出现的次数 -1−1;
如果此时「左括号」的数量为 00,「右括号」数量加 11。
通过这样的计数规则,得到的「左括号」和「右括号」的数量就是各自最少应该删除的数量。
方法一:回溯 + 剪枝
C++代码如下:
class Solution {
public:
vector<string> res;
vector<string> removeInvalidParentheses(string s) {
int lremove = 0;
int rremove = 0;
for (char c : s) {
if (c == '(') {
lremove++;
} else if (c == ')') {
if (lremove == 0) {
rremove++;
} else {
lremove--;
}
}
}
helper(s, 0, 0, 0, lremove, rremove);
return res;
}
void helper(string str, int start, int lcount, int rcount, int lremove, int rremove) {
if (lremove == 0 && rremove == 0) {
if (isValid(str)) {
res.push_back(str);
}
return;
}
for (int i = start; i < str.size(); i++) {
if (i != start && str[i] == str[i - 1]) {
continue;
}
// 如果剩余的字符无法满足去掉的数量要求,直接返回
if (lremove + rremove > str.size() - i) {
return;
}
// 尝试去掉一个左括号
if (lremove > 0 && str[i] == '(') {
helper(str.substr(0, i) + str.substr(i + 1), i, lcount, rcount, lremove - 1, rremove);
}
// 尝试去掉一个右括号
if (rremove > 0 && str[i] == ')') {
helper(str.substr(0, i) + str.substr(i + 1), i, lcount, rcount, lremove, rremove - 1);
}
if (str[i] == ')') {
lcount++;
} else if (str[i] == ')') {
rcount++;
}
// 当前右括号的数量大于左括号的数量则为非法,直接返回.
if (rcount > lcount) {
break;
}
}
}
inline bool isValid(const string & str) {
int cnt = 0;
for (int i = 0; i < str.size(); i++) {
if (str[i] == '(') {
cnt++;
} else if (str[i] == ')') {
cnt--;
if (cnt < 0) {
return false;
}
}
}
return cnt == 0;
}
};
方法二:广度优先搜索
C++代码如下:
class Solution {
public:
bool isValid(string str) {
int count = 0;
for (char c : str) {
if (c == '(') {
count++;
} else if (c == ')') {
count--;
if (count < 0) {
return false;
}
}
}
return count == 0;
}
vector<string> removeInvalidParentheses(string s) {
vector<string> ans;
unordered_set<string> currSet;
currSet.insert(s);
while (true) {
for (auto & str : currSet) {
if (isValid(str))
ans.emplace_back(str);
}
if (ans.size() > 0) {
return ans;
}
unordered_set<string> nextSet;
for (auto & str : currSet) {
for (int i = 0; i < str.size(); i++) {
if (i > 0 && str[i] == str[i - 1]) {
continue;
}
if (str[i] == '(' || str[i] == ')') {
nextSet.insert(str.substr(0, i) + str.substr(i + 1, str.size()));
}
}
}
currSet = nextSet;
}
}
};