(特别简单的一道题,没有难度,可能考验的就是编程能力,能不能短时间敲完代码,我是菜狗)
题目:
给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。
题解:
首先看一眼数据范围 s 中至多含 20 个括号,一看到这个 20,瞬间我就直接无脑用二进制枚举所有状态,然后写到最后,发现不对,因为要去重,去重前要排序,可能会超时
但当时想着可能要经过 ”是否是有效字符串“ 和 ”是否是最长字符串“,感觉经过两次筛选,应该不会超时
(我现在都没想到什么样例能让他超时,但是确实超了)
代码如下:
class Solution {
public:
bool test(string s) {
int flag = 0;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '(') flag++;
else if(s[i] == ')' && flag != 0) flag--;
else if(s[i] == ')' && flag == 0) return false;
}
if(flag == 0) return true;
else return false;
}
vector<pair<int, string> > ddd;
vector<string> res;
vector<string> removeInvalidParentheses(string s) {
vector<pair<bool, int> > flag;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '(') flag.push_back(make_pair(true, i));
if(s[i] == ')') flag.push_back(make_pair(false, i));
}
for(int i = 0; i < (1 << flag.size()); i++) {
int f = 0;
string temp = "";
for(int j = 0; j < flag.size(); j++) {
while(f < flag[j].second) {
temp = temp + s[f];
f++;
}
f++;
if(((i >> j) & 1) != 1) continue;
if(flag[j].first) temp = temp + '(';
else temp = temp + ')';
}
while(f < s.size()) {
temp = temp + s[f];
f++;
}
if(test(temp)) ddd.push_back(make_pair(temp.size(), temp));
}
int f = 0;
for(int i = 0; i < ddd.size(); i++) {
f = max(f, ddd[i].first);
}
for(int i = 0; i < ddd.size(); i++) {
if(ddd[i].first == f) {
res.push_back(ddd[i].second);
}
}
sort(res.begin(), res.end());
res.erase(unique(res.begin(), res.end()), res.end());
return res;
}
};
然后就没办法呗,只能避免去重,因为假如 ”(((((“,我们从中去除两个,只得到一种情况 “(((”,而二进制枚举的话一堆情况,难免要去重,因此我们进行 dfs,把一起出现的相同括号看成一组,比如 “(((((”,看成一种,递归的时候,只考虑 6 次,“”,“(”,… ,“(((((”,这样就不需要去重了,就可以过了
class Solution {
public:
bool test(string s) {
int flag = 0;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '(') flag++;
else if(s[i] == ')' && flag != 0) flag--;
else if(s[i] == ')' && flag == 0) return false;
}
if(flag == 0) return true;
else return false;
}
vector<pair<bool, int> > flag; // 记录连续的 '(' 或 ')' 出现的次数
string str; // 把字符串 s 存入全局变量
vector<string> solve(int a, int v, int p) {
vector<string> res;
string t = "";
for(int i = 0; i < v; i++) {
if(flag[a].first) t = t + '(';
else t = t + ')';
}
p = p + flag[a].second;
while(p < str.size() && str[p] != '(' && str[p] != ')') {
t = t + str[p];
p++;
}
if(a == flag.size() - 1) {
res.push_back(t);
return res;
}
vector<string> temp;
for(int i = 0; i <= flag[a + 1].second; i++) {
temp = solve(a + 1, i, p);
for(int j = 0; j < temp.size(); j++) {
res.push_back(t + temp[j]);
}
}
return res;
}
vector<string> removeInvalidParentheses(string s) {
vector<string> res;
vector<string> ddd;
str = s;
int p = 0;
while(p < s.size()) {
int f = 0;
if(p < s.size() && s[p] == '(') {
while(p < s.size() && s[p] == '(') {
p++;
f++;
}
flag.push_back(make_pair(true, f));
}
f = 0;
if(p < s.size() && s[p] == ')') {
while(p < s.size() && s[p] == ')') {
p++;
f++;
}
flag.push_back(make_pair(false, f));
}
while(p < s.size() && s[p] != '(' && s[p] != ')') {
p++;
}
}
if(flag.size() == 0) {
res.push_back(s);
return res;
}
vector<string> temp;
string t = "";
p = 0;
while(p < str.size() && str[p] != '(' && str[p] != ')') {
t = t + str[p];
p++;
}
for(int i = 0; i <= flag[0].second; i++) { // 遍历每组括号可以存在的括号数量
temp = solve(0, i, p);
for(int j = 0; j < temp.size(); j++) {
if(test(temp[j])) ddd.push_back(t + temp[j]);
}
}
int f = 0;
for(int i = 0; i < ddd.size(); i++) {
// 注意字符串的 size() 得到的不是 int 类型,需要强转
f = max(int(ddd[i].size()), f);
}
for(int i = 0; i < ddd.size(); i++) {
if(ddd[i].size() == f) {
res.push_back(ddd[i]);
}
}
return res;
}
};
但是呢,这样时间复杂度还是不是最优的,我们可以进行剪枝,因为实际上,我们是已知我们需要去掉几个括号的(对原始字符串遍历一遍),所以可以 dfs 多传一个参数,用作限制去掉的括号总数,为 0 就停止遍历,这样就可以优化,代码懒得写了