给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
题目来源:力扣(LeetCode)
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
在此方法中,我们利用两个计数器 left 和 right 。首先,我们从左到右遍历字符串,对于遇到的每个 ‘(’,我们增加 left 计数器,对于遇到的每个**‘)’** ,我们增加 right 计数器。每当 left 计数器与 right 计数器相等时,我们计算当前有效字符串的长度,并且记录目前为止找到的最长子字符串。当right 计数器比 \textit{left}left 计数器大时,我们将left 和 right 计数器同时变回 00。
这样的做法贪心地考虑了以当前字符下标结尾的有效括号长度,每次当右括号数量多于左括号数量的时候之前的字符我们都扔掉不再考虑,重新从下一个字符开始计算,但这样会漏掉一种情况,就是遍历的时候左括号的数量始终大于右括号的数量,即 (() ,这种时候最长有效括号是求不出来的。
解决的方法也很简单,我们只需要从右往左遍历用类似的方法计算即可,只是这个时候判断条件反了过来:
当left 计数器比 right 计数器大时,我们将 left 和 right 计数器同时变回 00
当 left 计数器与 right 计数器相等时,我们计算当前有效字符串的长度,并且记录目前为止找到的最长子字符串
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function(s) {
//设置left和right两个计数器,并将最长字符串变量初始化为0
let left = 0, right = 0, maxlength = 0;
//左循环
for (let i = 0; i < s.length;i++) {
//遍历到左括号时left计数器增加,否则right++
if (s.charAt(i) == '(') {
left++;
} else {
right++;
}
if (left == right) {
//当两个计数变量相等时赋值给结果变量,此时我们取左右循环后最大的数值
maxlength = Math.max(maxlength, 2 * right);
} else if (right > left) {
//当右括号比左括号多时候说明前面没有左括号和多出的右括号匹配,舍弃前面遍历,将left和right置零
left = right = 0;
}
}
//将两个计数变量置零准备右循环
left = right = 0;
for (let j = s.length - 1; j >= 0; j--) {
//右循环开始,与左循环逻辑相通
if (s.charAt(j) == '(') {
left++;
} else {
right++;
}
if (left == right) {
//此时我们取左右循环后最大的数值
maxlength = Math.max(maxlength, 2 * left);
} else if (left > right) {
//判断条件更改,当左括号大于右括号时候说明没有右括号匹配多余的左括号,故舍弃继续往前走
left = right = 0;
}
}
return maxlength;
};