地址 https://leetcode-cn.com/problems/remove-invalid-parentheses/
给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。
示例 1:
输入:s = "()())()"
输出:["(())()","()()()"]
示例 2:
输入:s = "(a)())()"
输出:["(a())()","(a)()()"]
示例 3:
输入:s = ")("
输出:[""]
提示:
1 <= s.length <= 25
s 由小写英文字母以及括号 '(' 和 ')' 组成
s 中至多含 20 个括号
解法
dfs 剪枝 但是包括太多细节需要注意
写了四版代码,前两版都TLE 超时了.
第一版超时代码
class Solution {
public:
vector<string> ans;
int visitedLeft = 0;
map<int, set<string>> mm;
void dfs(string s, int idx, string& t) {
if (idx == s.size()) {
if (0 == visitedLeft) {
mm[t.size()].insert(t);
}
return;
}
if (s[idx] == '(') {
//选择删除
dfs(s,idx+1,t);
//选择保留
t.push_back('(');
visitedLeft++;
dfs(s, idx + 1, t);
visitedLeft--;
t.pop_back();
}
else if(s[idx] == ')') {
//选择删除
dfs(s, idx + 1, t);
//如果之前有记录左括号才可能保留右括号
if (visitedLeft != 0) {
t.push_back(')');
visitedLeft--;
dfs(s, idx + 1, t);
visitedLeft++;
t.pop_back();
}
}
else {
//非括号的字符 直接存入
t.push_back(s[idx]);
dfs(s, idx + 1, t);
t.pop_back();
}
}
vector<string> removeInvalidParentheses(string s) {
string t;
dfs(s,0,t);
auto tt = mm.rbegin();
for (auto & e : tt->second) {
ans.push_back(e);
}
return ans;
}
};
第二版超时代码
class Solution {
public:
vector<string> ans;
int visitedLeft = 0;
int deleteCount = 0;
int minDeleteCount = 999999;
map<int, set<string>> mm;
void dfs(string s, int idx, string& t) {
if (idx == s.size()) {
if (0 == visitedLeft && minDeleteCount>= deleteCount) {
minDeleteCount = deleteCount;
mm[t.size()].insert(t);
}
return;
}
if (deleteCount > minDeleteCount) {
//删除过多 不考虑此分支
return;
}
if (s[idx] == '(') {
//选择删除
deleteCount++;
dfs(s, idx + 1, t);
deleteCount--;
//选择保留
t.push_back('(');
visitedLeft++;
dfs(s, idx + 1, t);
visitedLeft--;
t.pop_back();
}
else if (s[idx] == ')') {
//选择删除
deleteCount++;
dfs(s, idx + 1, t);
deleteCount--;
//如果之前有记录左括号才可能保留右括号
if (visitedLeft != 0) {
t.push_back(')');
visitedLeft--;
dfs(s, idx + 1, t);
visitedLeft++;
t.pop_back();
}
}
else {
//非括号的字符 直接存入
t.push_back(s[idx]);
dfs(s, idx + 1, t);
t.pop_back();
}
}
vector<string> removeInvalidParentheses(string s) {
string t;
dfs(s, 0, t);
auto tt = mm.rbegin();
for (auto & e : tt->second) {
ans.push_back(e);
}
return ans;
}
};
然后优化了下dfs中重复的选择 比如
class Solution {
public:
vector<string> ans;
int visitedLeft = 0;
map<int, set<string>> mm;
void dfs(const string& s, int idx, string& t) {
if (idx == s.size()) {
if (0 == visitedLeft) {
mm[t.size()].insert(t);
}
return;
}
if (s[idx] != '(' && s[idx] != ')') {
//不是括号则保留 并且继续下一位尝试
t.push_back(s[idx]);
dfs(s,idx+1,t);
t.pop_back();
return;
}
int k = 0;
for (int i = idx; i < s.size(); i++) {
if (s[idx] == s[i]) { k++; }
else { break; }
}
if (s[idx] == '(') {
// (符号
//根据有相同k个括号 决定 留几个删除几个
for (int i = 0; i <= k; i++) {
visitedLeft += i;
for(int j = 0;j<i;j++){ t.push_back('('); }
dfs(s, idx + k,t);
for (int j = 0; j < i; j++) { t.pop_back(); }
visitedLeft -= i;
}
}
else {
// )符号
//根据有相同k个括号 决定 留几个删除几个
for (int i = 0; i <= k; i++) {
if (i <= visitedLeft) {
visitedLeft -= i;
for (int j = 0; j < i; j++) { t.push_back(')'); }
dfs(s, idx + k, t);
for (int j = 0; j < i; j++) { t.pop_back(); }
visitedLeft += i;
}
}
}
}
vector<string> removeInvalidParentheses(string s) {
string t;
dfs(s, 0, t);
const auto& tmp = mm.rbegin();
for (auto& e : tmp->second) {
ans.push_back(e);
}
return ans;
}
};
然后在尝试添加一些优化 在某些DFS路径中,如果删除的次数已经比当前得到的尝试结果删除次数过,那么就不必继续尝试了,不可能得到更少次数的结果的,优化剪枝
class Solution {
public:
vector<string> ans;
int visitedLeft = 0;
map<int, set<string>> mm;
int minDelC = 999999;
int delCount = 0;
void dfs(const string& s, int idx, string& t) {
if (idx == s.size()) {
if (0 == visitedLeft && delCount<=minDelC) {
minDelC = delCount;
mm[t.size()].insert(t);
}
return;
}
if (delCount > minDelC) { return; }
if (s[idx] != '(' && s[idx] != ')') {
//不是括号则保留 并且继续下一位尝试
t.push_back(s[idx]);
dfs(s,idx+1,t);
t.pop_back();
return;
}
int k = 0;
for (int i = idx; i < s.size(); i++) {
if (s[idx] == s[i]) { k++; }
else { break; }
}
if (s[idx] == '(') {
// (符号
//根据有相同k个括号 决定 留几个删除几个
for (int i = 0; i <= k; i++) {
visitedLeft += i;
delCount += (k - i);
for(int j = 0;j<i;j++){ t.push_back('('); }
dfs(s, idx + k,t);
for (int j = 0; j < i; j++) { t.pop_back(); }
delCount -= (k - i);
visitedLeft -= i;
}
}
else {
// )符号
//根据有相同k个括号 决定 留几个删除几个
for (int i = 0; i <= k; i++) {
if (i <= visitedLeft) {
visitedLeft -= i;
delCount += (k - i);
for (int j = 0; j < i; j++) { t.push_back(')'); }
dfs(s, idx + k, t);
for (int j = 0; j < i; j++) { t.pop_back(); }
delCount -= (k - i);
visitedLeft += i;
}
}
}
}
vector<string> removeInvalidParentheses(string s) {
string t;
dfs(s, 0, t);
const auto& tmp = mm.rbegin();
for (auto& e : tmp->second) {
ans.push_back(e);
}
return ans;
}
};