LeetCode32、最长有效括号

89 阅读1分钟

LeetCode 系列记录我学习算法的过程。

持续创作,加速成长!这是我参与「掘金日新计划 6 月更文挑战」的第 28 天,点击查看活动详情

题目

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例:

输入: s = "(()"
输出: 2
解释: 最长有效括号子串是 "()"


输入: s = ")()())"
输出: 4
解释: 最长有效括号子串是 "()()"


输入: s = ""
输出: 0

提示

  • 0 <= s.length <= 3 * 104
  • s[i] 为 '(' 或 ')'

思路

又是一道困难级的题目,既然是找最长有效的括号子串,那么左右括号的数量必须是一样的,且需左括号开头:

  • 首先定义两个指针,一个记录开始遍历位置 left,一个进行遍历 right
  • 然后定义两个变量 lrrr 存储左右括号数量,一个变量 res 存储最大的有效长度
  • 外层遍历的结束条件是剩余字符个数不大于 res
  • 每次外层遍历都要重置 right 值为 left,重置 lrrr0
  • 内层遍历结束条件为 right 到达边界或 lr 大于剩余字符数的一半(此时肯定不能凑齐有效字符串)
  • 内层遍历判断 right 位置字符进行 lrrr 自增
  • 如果此时 rr 大于 lr,则结束内层循环进行下一次外层循环
  • 如果 lr 等于 rr ,则判断是否需要覆盖 res 的值
  • 最后遍历结束返回 res 的值

代码实现

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function(s) {
    let left = 0, // 记录开始遍历位置
        right = 0,  // 遍历指针
        len = s.length,  // 字符串长度
        res = 0,  // 记录结果
        lr = 0,  // 左括号数量
        rr = 0  // 右括号数量
    // 外层循环,当剩余字符数不大于 res 时结束循环
    while(len - left > res) {
        // 每次循环重置 righ、lr、rr 的值 
        right = left ,lr = 0, rr = 0
        // 内层循环,当左括号数大于剩余字符的一半或 right 到达边界时结束循环
        while(lr <= (len - left) / 2 && right < len) {
            // 当前遍历字符为 ( 时,lr自增
            if (s[right] === '(') {
                lr++
            } else {
                // 反之 rr 自增
                rr++
            }
            // 如果左右括号数一样
            if (lr === rr) {
                // 更新 res 的值
                res = Math.max(res, lr + rr)
            }
            // 如果右括号数大于左括号数,结束内层循环
            if (rr > lr) {
                break
            }
            // 进入下次内层循环
            right++
        }
        // 进入下次外层循环
        left++
    }
    // 返回结果
    return res
};

image.png

优化

执行耗时太不理想了,可能是用的方法太笨了,暴力解题

const longestValidParentheses = (s) => {
  let maxLen = 0;
  const stack = [];
  stack.push(-1);
  for (let i = 0; i < s.length; i++) {
    const c = s[i];
    if (c == '(') {       // 左括号的索引,入栈
      stack.push(i);
    } else {              // 遍历到右括号
      stack.pop();        // 栈顶的左括号被匹配,出栈
      if (stack.length) { // 栈未空
        const curMaxLen = i - stack[stack.length - 1]; // 计算有效连续长度
        maxLen = Math.max(maxLen, curMaxLen);          // 挑战最大值
      } else {            // 栈空了
        stack.push(i);    // 入栈充当参照
      }
    }
  }
  return maxLen;
};

image.png