Problem: 32. 最长有效括号
思路
做热题100做到的,看到是Hard的dp,直接投降了,寻思另一种写法。于是去评论区逛了下,有位同学提到了用栈+合并区间的思路,于是以此为线索,开始思考此题的解法。
解题方法
个人习惯阅读题干,将信息消化,而后逐步击破。此题要求我们求【最长有效括号】
那么可以拆解成2个问题
- 有效括号
- 最长
我的想法是通过一个栈去存储字符串中的(和)(注意,存的是inedx),当遍历到)时,判断此时栈顶元素(即stk.pop())是否是(,如果是,则用一个结果数组(即result)去记录此时出现的有效括号()的index。
拿示例2举个例子:
")()())"
-
遍历此字符串,当遍历到
(时,此时往stk里push它的index,即1 -
而后继续遍历,当遍历到
)时,判断栈顶元素是否是(,代码判断如下:jsif (s[i] === ')') { let top = stk.pop() // 即 s[1] === '(' if (s[top] === '(') { result.push([top, i]) } } -
如果是,则代表我们遇到了1个有效括号,此时往
result里存储此括号的左右下标。js// 即 result.push([1,2]) result.push([top, i])
当我们遍历完毕整个s之后,我们就会得到这样一个result数组:[[1,2],[3,4]]
接下来我们要做的就是合并区间,可以参考一下这道题哦:56. 合并区间
不过比这题还要多一种合并区间的情况,即就算区间不重叠,但是相邻的话,也要合并。
即,我们要合并重叠区间,也要合并相邻区间
回到此题,我们对result执行合并区间的操作,得到最终的target数组:[1,4],此时,最长 这个问题也迎刃而解了,就是4 - 1 + 1,即 4
这里方便理解我再举1个例子:
"((((()))))("
得到的result数组长这样:
[ [ 4, 5 ], [ 3, 6 ], [ 2, 7 ], [ 1, 8 ], [ 0, 9 ] ]
按照左边界排序一下
[ [ 0, 9 ], [ 1, 8 ], [ 2, 7 ], [ 3, 6 ], [ 4, 5 ] ]
然后执行合并区间的操作,得到target
[0,9],最终最长的答案也就是10
复杂度
时间复杂度:
O(n)
空间复杂度:
O(n)
Code
js
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function (s) {
let stk = []
let result = [];
for (let i = 0; i < s.length; i++) {
if (s[i] === ")" && !stk.length) {
continue;
}
if (s[i] === '(') {
stk.push(i);
}
if (s[i] === ')') {
let top = stk.pop()
if (s[top] === '(') {
result.push([top, i])
}
}
}
// 开始合并数组
result.sort((a, b) => a[0] - b[0])
let targets = [];
let ans = 0;
// 每次合并完数组之后,计算一次长度,和ans做一次比较,取最大的。
for (let i = 0; i < result.length; i++) {
if (!targets.length) {
let temp = result[i][1] - result[i][0] + 1
ans = Math.max(ans, temp)
targets = result[i]
}
else {
if (targets[1] > result[i][1]) {
let temp = targets[1] - targets[0] + 1
ans = Math.max(ans, temp)
}
if (targets[1] + 1 === result[i][0]) {
let temp = result[i][1] - targets[0] + 1
ans = Math.max(ans, temp)
targets = [targets[0], result[i][1]]
}
if (targets[1] < result[i][0] - 1) {
targets = result[i]
let temp = result[i][1] - result[i][0] + 1
ans = Math.max(ans, temp)
}
}
}
return ans;
};