题目来源
题目描述
class Solution {
public:
vector<string> removeInvalidParentheses(string s) {
}
};
题目解析
分析题目
- n≤30, 指数级别,dfs+剪枝,状态压缩dp
- s 由小写英文字母以及括号 ‘(’ 和 ‘)’ 组成
前置题
分析题意
-
因为要的是所有结果,所以允许暴力遍历
-
所有结果中:
- 字面值一样的只允许返回一份
- 如果有多种选择,那么不同的字面值都要返回
-
我们需要让字符串变成一个有效的字符串
-
第一个要解决的问题是:如何判断一个字符串是否是有效的
如何判断一个字符串是否是有效的( s 由小写英文字母以及括号 ‘(’ 和 ‘)’ 组成)
- 先考虑最简单的情况,这里假设只有
)
可能多出来的情况 - 从头到尾遍历整个字符串
- 维持变量
i
,
j
i,j
i,j:
- i:当前正在检查的位置
- j j j:可能删除的位置
- 刚开始时 i , j i,j i,j都在 0 0 0位置
- 维持变量count
- 初始时count = 0
- 然后遍历过程中,遇到
(
,count++;遇到)
,count– - 如果一直count>=0,说明每一个
)
都能找到与之匹配的(
- 如果某个位置count<0,说明就要删除了
- 维持变量
i
,
j
i,j
i,j:
举个例子
遍历数组:
- 假设有
(
可能多出来的情况
将字符串反转,和上面的操作一样
实现
class Solution {
public:
vector<string> removeInvalidParentheses(string s) {
vector<string> res;
remove(move(s), {'(', ')'}, 0, 0, res);
return res;
}
void remove(std::string s, const vector<char>& par, int checkIndex, int deleteIndex, vector<string>& res) {
//m为当前遍历到的需要修改的位置(即左括号<右括号时的位置),n为上一次修改的右括号位置
int count = 0; //用于 记录左括号数-右括号
for(int currCheck = checkIndex; currCheck < s.size(); currCheck ++) { //i从m往后遍历:遍历到“需要修改的子串”的终止位置,停下
if(s[currCheck] == par[0]) count++; //是左括号++
if(s[currCheck] == par[1]) count--; //是右括号--
if(count >= 0) continue; //(1)左括号数量多于右括号,不执行下面的,继续遍历
//(2)左括号数量少于右括号,开始找要删除的右括号
for(int mayDelete = deleteIndex; mayDelete <= currCheck; mayDelete++) { //j从n往后遍历到i:寻找要删除的右括号
if(s[mayDelete] == par[1] && (mayDelete == deleteIndex || s[mayDelete - 1] != s[mayDelete])) {
auto ss = s.substr(0, mayDelete) + s.substr(mayDelete + 1);
remove(move(ss), par, currCheck, mayDelete, res);
}
}
return;
}
//将s逆转
reverse(s.begin(), s.end());
if(par[0]=='(')
remove(move(s), {par[1], par[0]}, 0, 0, res);
else
res.push_back(move(s));
}
};