题目链接
删除无效的括号
题目描述
注意点
- s 由小写英文字母以及括号 ‘(’ 和 ‘)’ 组成
- 1 <= s.length <= 25
- 返回所有可能的结果。答案可以按 任意顺序 返回
解答思路
- 首先计算删除无效的括号最少次数需要删除的左括号和右括号的数量,方法是:设置两个遍历leftBracket和rightBracket,如果当前字符为’(‘,则leftBracket加1;如果当前字符为’)',则分情况考虑,如果次数leftBracket为0,则rightBracket加1(要形成有效括号必须删除一个右括号),如果leftBracket大于0,则leftBracket减1
- 深度优先遍历找到删除和不删除当前括号的情况是否有效,深搜结束有几种情况:一是已达到最少次数需要删除的左括号和右括号的数量;二是已访问到字符串尾部
- 同时要注意进行剪枝,例如当前字符不是括号可不考虑删除该字符的情况,此时左括号数量等于右括号数量则不能再添加右括号
- 还要注意已达到最少次数需要删除的左括号和右括号的数量时连接字符串尾部判断最后组成的字符串括号是否有效
代码
class Solution {
public List<String> removeInvalidParentheses(String s) {
int leftBracket = 0, rightBracket = 0;
List<String> res = new ArrayList<>();
// 查找多余的左右括号数量
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != '(' && s.charAt(i) != ')') {
continue;
}
if (s.charAt(i) == '(') {
leftBracket++;
} else if (leftBracket == 0) {
rightBracket++;
} else {
leftBracket--;
}
}
StringBuilder sb = new StringBuilder();
dfs(s, sb, res, 0, 0, 0, leftBracket, rightBracket);
return res;
}
public void dfs(String s, StringBuilder sb, List<String> res, int idx, int leftBracketSum, int rightBracketSum, int leftBracket, int rightBracket) {
// 左括号比右括号少,无法匹配
if (leftBracketSum < rightBracketSum) {
return;
}
// 多余的左右括号已全部移除,可直接返回结果
if (leftBracket == 0 && rightBracket == 0) {
int start = sb.length();
for (int i = idx; i < s.length(); i++) {
if (s.charAt(i) == '(') {
leftBracketSum++;
}
if (s.charAt(i) == ')') {
rightBracketSum++;
// 右括号多于左括号
if (rightBracketSum > leftBracketSum) {
sb.delete(start, sb.length());
return;
}
}
sb.append(s.charAt(i));
}
if (!res.contains(sb.toString())) {
res.add(sb.toString());
}
int end = sb.length();
sb.delete(start, sb.length());
return;
}
// 已越界
if (idx >= s.length()) {
return;
}
// 非括号字符无影响
if (s.charAt(idx) != '(' && s.charAt(idx) != ')') {
sb.append(s.charAt(idx));
dfs(s, sb, res, idx + 1, leftBracketSum, rightBracketSum, leftBracket, rightBracket);
sb.deleteCharAt(sb.length() - 1);
return;
}
// 移除当前符号和不移除分别考虑
if (s.charAt(idx) == '(') {
// 不移除
sb.append(s.charAt(idx));
dfs(s, sb, res, idx + 1, leftBracketSum + 1, rightBracketSum, leftBracket, rightBracket);
sb.deleteCharAt(sb.length() - 1);
// leftBracket小于等于0该类括号不能再被移除,否则不是最小次数
if (leftBracket > 0) {
dfs(s, sb, res, idx + 1, leftBracketSum, rightBracketSum, leftBracket - 1, rightBracket);
}
}
if (s.charAt(idx) == ')') {
// 不移除
sb.append(s.charAt(idx));
dfs(s, sb, res, idx + 1, leftBracketSum, rightBracketSum + 1, leftBracket, rightBracket);
sb.deleteCharAt(sb.length() - 1);
// rightBracket小于等于0该类括号不能再被移除,否则不是最小次数
if (rightBracket > 0) {
dfs(s, sb, res, idx + 1, leftBracketSum, rightBracketSum, leftBracket, rightBracket - 1);
}
}
}
}
关键点
- 计算删除无效的括号最少次数需要删除的左括号和右括号的数量的方法
- 深搜时剪枝的情况