LeetCode-032:最长有效括号,用栈把“匹配长度”一次算清

本题在线练习:LeetCode 32. 最长有效括号 - 在线练习(免费 · 无需登录 · AI 辅助)(https://onefly.top/zero2Leetcode/playground.html?id=32)

配套刷题网站 Zero2Leetcode - 内置本地 OJ + AI 教练,零门槛开刷 Hot 100。

题目概述

给定只包含 '('')' 的字符串 s,返回最长有效(格式正确且连续)的括号子串长度。

例如:

  • s = ")()())" -> 最长有效子串是 "()()",长度 4

核心思路:用栈存“尚未匹配的下标”,并维护一个基准

“有效括号”本质是匹配问题,而匹配最适合用栈:

  • 遇到 '(':把下标入栈(等待匹配)
  • 遇到 ')':尝试弹出一个 '(' 与之匹配

难点在于:如何计算“当前能形成的有效长度”?

关键技巧是:在栈底放一个“最后一个不合法位置”的基准下标 base

常见写法:

  • 栈初始化为 [-1]
    • -1 表示在字符串开始之前的一个虚拟下标

遍历每个位置 i

  1. 如果 s[i] == '(',入栈 i
  2. 否则(右括号):
    • 弹栈一次(匹配一个 '('
    • 如果弹完栈为空,说明当前右括号无法匹配:把 i 入栈作为新的基准
    • 如果栈不空,当前有效长度是 i - stack[-1]

代码实现(栈)

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        stack = [-1]
        ans = 0

        for i, ch in enumerate(s):
            if ch == '(':
                stack.append(i)
            else:
                stack.pop()
                if not stack:
                    # 没有可以作为基准的下标了:当前 i 是新的“不合法起点”
                    stack.append(i)
                else:
                    ans = max(ans, i - stack[-1])

        return ans

逐行拆解

1)为什么要先放 -1

如果字符串一开始就形成合法括号,比如 "()"

  • 处理到 i=1 时,弹出 '(' 后栈里还应有一个基准
  • 这时长度应为 1 - (-1) = 2

所以需要 -1 作为最初基准。

2)为什么栈空时要把 i 入栈

当遇到无法匹配的 ')',比如 ")(" 的第一个字符:

它会把之前所有可能的有效子串都截断,后续的合法子串必须从它后面开始。

i 入栈,就相当于设置新的基准。

手动模拟

s = ")()())"

初始化:stack = [-1]

  • i=0, ')':pop -> 栈空,push(0) -> [0]
  • i=1, '(':push(1) -> [0,1]
  • i=2, ')':pop -> [0],长度 2-0=2,ans=2
  • i=3, '(':push(3) -> [0,3]
  • i=4, ')':pop -> [0],长度 4-0=4,ans=4
  • i=5, ')':pop -> 栈空,push(5) -> [5]

最终 ans=4。

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)(最坏情况下全是 '('

总结

这题的栈解法真正“值钱”的点不是用栈本身,而是这个基准技巧:

栈里永远保留一个“最后一个不合法位置”的下标,让 i - stack[-1] 直接得到当前可用的合法长度。

掌握这个思路后,很多括号匹配的“最长/最短/计数”变体都会顺手很多。

posted @ 2026-03-27 01:18  孤飞  阅读(62)  评论(0)    收藏  举报