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:
- 如果
s[i] == '(',入栈i - 否则(右括号):
- 弹栈一次(匹配一个
'(') - 如果弹完栈为空,说明当前右括号无法匹配:把
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=2i=3, '(':push(3) ->[0,3]i=4, ')':pop ->[0],长度4-0=4,ans=4i=5, ')':pop -> 栈空,push(5) ->[5]
最终 ans=4。
复杂度分析
- 时间复杂度:
O(n) - 空间复杂度:
O(n)(最坏情况下全是'(')
总结
这题的栈解法真正“值钱”的点不是用栈本身,而是这个基准技巧:
栈里永远保留一个“最后一个不合法位置”的下标,让
i - stack[-1]直接得到当前可用的合法长度。
掌握这个思路后,很多括号匹配的“最长/最短/计数”变体都会顺手很多。

浙公网安备 33010602011771号