题目描述
思路解析动画文字版
遇到左括号就压进栈;遇到右括号,就看栈顶的左括号能不能和它配成一对——能配就弹出栈顶,不能配就说明不合法。
准备:上面是要处理的字符串,下面是我们的栈。开始逐个字符处理。
第 0 个:'(':'(' 是左括号,压入栈。栈:[ ( ]
第 1 个:'[':'[' 也是左括号,压入栈。栈:[ (, [ ],栈顶是 '['。
第 2 个:']':']' 是右括号。看栈顶是 '[',正好是一对!可以把栈顶弹出去。
第 2 个:弹出:配对成功,弹出栈顶 '['。栈剩下:[ ( ]。
第 3 个:')':')' 是右括号。栈顶是 '(',又是一对!弹出。
第 3 个:弹出:弹出 '(',栈又空了。
结束:字符串走完,栈正好空了——说明每个左括号都找到了对应的右括号,返回 true。
两种情况:① 右括号来了但栈顶配不上;② 字符串结束时栈还没空(有左括号没人配)。来看个反例。
反例 "(]" · '(':处理 "(]":先把 '(' 压入栈。
反例 · ']':遇到 ']',可栈顶是 '(',对不上号——立刻返回 false。
只有一种括号时,确实可以用一个计数器:左加一、右减一,全程不为负、最后归零就合法。但一旦有多种括号、还能交叉,比如 "([)]",光数个数就废了——来看这个最坑的例子。
交叉反例 "([)]" · 读 '(':先读第 0 个 '(',是左括号,压入栈。栈:[ ( ]。
交叉反例 · 读 '[':再读第 1 个 '[',也是左括号,入栈。两个左括号都进来了。注意:要是只用计数器,此刻「左括号 = 2」,看不出谁套谁。
交叉反例 · ')' 来了:读到 ')',它该配 '(';可最近的那个左括号是 '['——顺序乱了,返回 false。计数器只会说「左 2 右 1,还没数完」,根本发现不了这个交叉错误。栈记住了「最近的左括号是谁」,这正是计数器给不了的。
凡是「最近出现的要最先被匹配/抵消」的问题,都该想到栈:逆波兰表达式、字符串解码、消消乐式的相邻消除……
边界三连:有效的括号 的边界先看最小规模、特殊输入和最容易触发分支的样例。
① 为什么用栈不用计数器?——只有一种括号能计数,但 "([)]" 这种多类型交叉必须靠栈记住「最近的左括号是谁」。② 能提前剪枝吗?——能:长度是奇数直接 false;右括号配不上立即 return。③ 为什么结束还要判栈空?——像 "(" 这种走完栈里还剩没配对的左括号,要返回 false。
「栈 = 最近的先处理」是一整类题的内核:LC394 字符串解码(遇到 ] 弹出最近一段重复)、LC1047 相邻消除,再进阶到 LC739 / LC42 的单调栈(遇到更大的就回头结算)。学会这一道,栈这一类就入门了——更多在 栈专题 继续,或让小欧私教陪你把这套骨架套到下一题。
面试追问:这三问都不是复读前面,而是变体:混入杂字符、改成「补几个」、退化成单类型。把骨架讲成自己的话,才扛得住追问。
参考代码
class Solution: def isValid(self, s): stack = [] pairs = {')': '(', ']': '[', '}': '{'} for ch in s: if ch in pairs: # 右括号 if not stack or stack.pop() != pairs[ch]: return False else: stack.append(ch) # 左括号入栈 return not stack # 栈空才合法复杂度
- 时间复杂度:O(n),每个字符最多入栈、出栈各一次 → O(n)
- 空间复杂度:O(n),最坏全是左括号(如 "((((")全压栈 → O(n)
可套用的代码模板
把本题三件事抽象成三个空:该入栈=是左括号、能抵消=栈顶左括号和它成对、收尾=要求栈空。换成「相邻字符相同就消」就是 LC1047,换成「数字算符」就是逆波兰——填这三个空即可。右上角可切 C++ / Java。
# 凡是「相邻可抵消 / 最近优先匹配」都套这个骨架stack = []for x in 序列: if 该入栈(x): # 把 x 留着等以后配 stack.append(x) elif stack and 能抵消(stack[-1], x): # 和栈顶抵消 stack.pop() # 抵消就弹掉 else: 失败处理() # 栈空/对不上 → 视题 return 或 push xreturn 收尾(stack) # 本题=要求栈空;别的题=返回栈内剩余易错点
面试追问把动画讲成自己的话
追问如果串里还混着字母、空格等非括号字符(如 "a(b)c")怎么办?
追问进阶:LC921「使括号有效的最少添加」要返回还差几个,怎么改?
追问若题目改成只有一种括号(如 LC1021),还需要栈吗?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
最小栈
LeetCode 155 · 中等 · 沿着 栈 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题