960 字
5 分钟
删除无效的括号

题目描述#

给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。

返回所有可能的结果。答案可以按 任意顺序 返回。

解题思路#

  1. 最小删除量计算:遍历字符串,统计未匹配的左右括号数量 lremove/rremove(需删除的最少括号数)。
  2. 回溯搜索:从起始位置遍历字符串,递归尝试删除每个无效括号:
    • 跳过连续重复括号避免重复解
    • 剩余字符不足时剪枝
    • 删除左括号或右括号后更新对应删除量
  3. 结果验证:当删除量归零时,用栈验证括号有效性:
    • 遇左括号计数+1,遇右括号计数-1
    • 中途出现负值立即终止
    • 最终计数为零则为有效解

关键洞察#

  1. 删除量确定性:最小删除量 (lremove,rremove) 是固定值,直接作为搜索边界。
  2. 重复括号优化:跳过连续相同括号(str[i] === str[i-1]),避免生成重复解。
  3. 双效剪枝
    • 资源剪枝:剩余字符数 < lremove+rremove 时终止
    • 逻辑剪枝:优先删除无效括号缩小搜索空间
  4. 延迟验证:仅在删除完成时检查有效性,减少中间状态验证开销。

复杂度分析#

指标说明
时间复杂度O(n·2^n):最坏情况每个括号有删/留选择(n≤25 实际剪枝高效)
空间复杂度O(n²):递归深度 O(n),每层 substr 创建新字符串(O(n))
验证复杂度O(n):isValid 单次遍历,仅终点调用

:剪枝策略使实际性能远优于理论最坏复杂度,字符串约束(n≤25)保证可行性。

代码实现#

递归版本

/**
* @link {https://leetcode.cn/problems/remove-invalid-parentheses}
* @param {string} s
* @return {string[]}
*/
var removeInvalidParentheses = function(s) {
const helper = (str, start, lremove, rremove) => {
if (lremove === 0 && rremove === 0) {
if (isValid(str)) {
res.push(str);
}
return;
}
for (let i = start; i < str.length; i++) {
if (i !== start && str[i] === str[i - 1]) {
continue;
}
// 如果剩余的字符无法满足去掉的数量要求,直接返回
if (lremove + rremove > str.length - i) {
return;
}
// 尝试去掉一个左括号
if (lremove > 0 && str[i] === '(') {
helper(str.substr(0, i) + str.substr(i + 1), i, lremove - 1, rremove);
}
// 尝试去掉一个右括号
if (rremove > 0 && str[i] === ')') {
helper(str.substr(0, i) + str.substr(i + 1), i, lremove, rremove - 1);
}
}
}
const res = [];
let lremove = 0;
let rremove = 0;
for (const c of s) {
if (c === '(') {
lremove++;
} else if (c === ')') {
if (lremove === 0) {
rremove++;
} else {
lremove--;
}
}
}
helper(s, 0, lremove, rremove);
return res;
}
const isValid = (str) => {
let cnt = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === '(') {
cnt++;
} else if (str[i] === ')') {
cnt--;
if (cnt < 0) {
return false;
}
}
}
return cnt === 0;
}

迭代版本

const removeInvalidParentheses = (s) => {
const isValid = (str) => {
let balance = 0;
for (const c of str) {
if (c === '(') balance++;
else if (c === ')') balance--;
if (balance < 0) return false;
}
return balance === 0;
};
let queue = new Set([s]);
while (queue.size) {
const nextQueue = new Set();
const validResults = [];
for (const expr of queue) {
if (isValid(expr)) {
validResults.push(expr);
}
// 找到有效表达式后停止生成下一层
if (validResults.length) continue;
// 生成所有删除一个括号的表达式
for (let i = 0; i < expr.length; i++) {
if (expr[i] !== '(' && expr[i] !== ')') continue;
const newExpr = expr.slice(0, i) + expr.slice(i + 1);
nextQueue.add(newExpr);
}
}
if (validResults.length) return validResults;
queue = nextQueue;
}
return [""];
};

实际应用场景#

  1. 公式编辑器: 自动修复数学公式中的括号不匹配`
  2. SQL解析器: 修复嵌套查询中的括号错误`
  3. 编译器前端: 处理代码中的括号不匹配错误`
  4. 交互式教程: 括号匹配的编程教学工具`

相似题目#

删除无效的括号
https://website-truelovings-projects.vercel.app/posts/algorithms/删除无效的括号/
作者
欢迎来到StarSky的网站!
发布于
2025-08-09
许可协议
CC BY-NC-SA 4.0