携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情
前言
- leetcode hot100,是大厂面试高频题,也是必刷算法题。精选了100道LeetCode上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,按照官方说的,熟练掌握这 100 道题,就具备了代码世界通行的基本能力。
leetcode301题(删除无效的括号)
本文来讲hot100第301题(删除无效的括号),本题是括号类型的题目,本题解主要是用到和回溯+减枝,此题如果不理解括号匹配规则,建议先把20题“有效的括号”先做一下。
给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。
示例:
输入: s = "()())()"
输出: ["(())()","()()()"]
输入: s = "(a)())()"
输出: ["(a())()","(a)()()"]
输入: s = ")("
输出: [""]
提示:
1 <= s.length <= 25s由小写英文字母以及括号'('和')'组成s中至多含20个括号
分析
- 字符串由“字母”与“数字”构成
- 括号是成对存在的,所以删除n个括号后,最终的括号量一定是个偶数
- 删除最小数量的括号,可能这个最小数量会有多种结果,所以是返回数组
- 字符串是否合理与字母无关
思路
- 先一次遍历计算出多余的左括号和右括号
- 如果是左括号,则left ++
- 如果是右括号,判断left是不是为0,不为0则left--,为0则right++
- 通过这样的计数规则,可以算出左括号和右括号需要删除的最小数量
- 使用回溯算法遍历,去掉不合法的括号(需要减枝)
- 针对2,我们需要使用个方法判断是否合法
代码
var removeInvalidParentheses = function (s) {
let l = 0,
r = 0;
const ans = [];
for (const char of s) {
if (char === "(") {
l++;
}
if (char === ")") {
if (l === 0) {
r++;
} else {
l--;
}
}
}
// 回溯算法 + 减枝
function helper(str, start, l, r) {
if (l === 0 && r === 0) {
if (isValid(str)) {
ans.push(str);
}
return;
}
for (let i = start; i < str.length; i++) {
if (i !== start && str[i] === str[i - 1]) {
continue;
}
// 如果剩余的字符无法满足去掉的数量要求,直接返回
if (l + r > str.length - i) {
return;
}
// 尝试去掉一个左括号
if (l > 0 && str[i] === "(") {
helper(str.substr(0, i) + str.substr(i + 1), i, l - 1, r);
}
// 尝试去掉一个右括号
if (r > 0 && str[i] === ")") {
helper(str.substr(0, i) + str.substr(i + 1), i, l, r - 1);
}
}
}
helper(s, 0, l, r);
return ans;
};
function isValid(str) {
let cnt = 0;
for (const char of str) {
if (char === "(") {
cnt++;
} else if (char === ")") {
cnt--;
if (cnt < 0) {
return false;
}
}
}
return cnt === 0;
}
结语
本题解复杂点主要在于helper方法,不仅仅需要理解括号匹配规则,还需要知道回溯+减枝的方法,时间复杂度O(n * 2^n),空间复杂度O(n^2)