题目
给你一个由若干括号和字母组成的字符串 s
,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回
示例 1:
输入:s = "()())()"
输出:["(())()","()()()"]
示例 2:
输入:s = "(a)())()"
输出:["(a())()","(a)()()"]
示例 3:
输入:s = ")("
输出:[""]
提示:
1 <= s.length <= 25
s 由小写英文字母以及括号 '(' 和 ')' 组成
s 中至多含 20 个括号
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-invalid-parentheses
一、解题思路
- 首先定义m,表示从 [0, m-1] 这一段都是左括号数量比右括号多。 n 表示上一次在这个位置删除了一个右括号。
- 从第 0 个位置依次向右扫描,一旦发现右括号数>左括号数,就删除一个 [0, 当前位置] 的范围的右括号。删除掉后,[0, 当前位置] 就是一个符合条件的括号匹配,继续向右扫描,直到所有不符合条件的右括号都被删除。
- 把第 2 步得到的字符串,反转,按照同样的思路,把多出来的“右括号”删除。
- 最后的所有可行值中可能出现重复的括号搭配,需要进行去重。
二、结果
1.注意点
- 是否有非括号的字母数字等字符,需要跳过;
- 考虑重复值的出现;
2.C++代码
代码如下(示例):
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 m, int n, vector<string>& res) {
//m为当前遍历到的需要修改的位置(即左括号<右括号时的位置),n为上一次修改的右括号位置
int stack = 0; //用于 记录左括号数-右括号
for(int i=m; i<s.size(); i++) { //i从m往后遍历:遍历到“需要修改的子串”的终止位置,停下
if(s[i] == par[0]) stack++; //是左括号++
if(s[i] == par[1]) stack--; //是右括号--
if(stack >= 0) continue; //(1)左括号数量多于右括号,不执行下面的,继续遍历
//(2)左括号数量少于右括号,开始找要删除的右括号
for(int j=n; j<=i; j++) { //j从n往后遍历到i:寻找要删除的右括号
if(s[j]==par[1] && (j==n || s[j-1]!=par[1])) {
//j处是右括号 && j==n保证第一次顺利执行||前一个不是右括号,如果前面的和我是紧挨着的右号,删除前面的和删我有什么区别(这里是去重)
//为什么j==n一定可以执行? 因为n是上一次 修改的右括号 的位置
//这个地方以前是右括号,我给删掉了
//现在如果这个地方变成左括号了,那好,继续看后面的右括号
//如果这个地方又是右括号了,那不就是我上一层做的事情吗?我要再删除一次,直到我见到左括号
auto ss = s.substr(0, j) + s.substr(j+1);
remove(move(ss), par, i, j, res);
}
}
return;
}
//将当前子串逆转
reverse(s.begin(), s.end());
//处理左括号,为什么要逆置处理左括号?
//因为上面的遍历保证的是左括号>=右括号
//这次我们再保证右括号>=左括号,即可保证左括号==右括号,即匹配
//仔细推敲:数目相等其实未必匹配,但我们处理的时候是一发现不匹配就修改的
//即相当于解决每一个小错,相当于没有大错,需要自己体会一下
//此时传参互换了左右括号的位置,所以处理完左括号再执行到这步时候会执行else
if(par[0]=='(')
remove(move(s), {par[1], par[0]}, 0, 0, res);
else
res.push_back(move(s));
}
};
总结
python中的set可以很好的解决重复的问题 但是python的是解释性语言,比较慢。
打开第一天,坚持坚持 加油加油!!!!!