20. 有效的括号(简单)

Blind 75 › 20. 有效的括号(简单) (第 16 章)
文章工具

题目

给定一个只由 ( ) { } [ ] 这六种字符组成的字符串 s,判断它是不是「合法括号串」。

合法需要同时满足:

  • 每个左括号 (、{、[ 都必须用同类型的右括号闭合;
  • 闭合顺序不能交叉:先出现的左括号必须后闭合;
  • 每个右括号之前,都要有对应的同类型左括号。

换句话说:扫描时遇到一个右括号,它必须能马上和「最近一个还没闭合的左括号」配对,配不上就不合法。

自造示例:

s结果一句话原因
"{[()]}"true内层 () 先合,再依次合 []、{}
"[]({})"true两段独立分组,各自配对正确且互不交叉
"([)]"false括号交叉:( 还没闭合就来了错类型的 )
")("false右括号先出现,前面没有可配对左括号
"((()"false扫描结束后仍有左括号未闭合

约束:1 ≤ s.length ≤ 104;s 仅由上述六种括号字符组成。

思路

一句话:遇到左括号就存起来,遇到右括号就检查「最近存进去的那个」是不是同类型。

最直白的想法是「消消乐」:反复删除相邻且同类型的闭合对 "()"、"[]"、"{}",直到不能再删;如果最后删空了,就说明合法。

例如 "{[()]}":先删 "()" 得 "{[]}",再删 "[]" 得 "{}",最后删 "{}" 得空串,返回 true。

这个方法直观又正确,但每一轮都要从头扫一遍;像 "((((...))))" 这种深嵌套串,每轮只能从最中间拆掉一层,最坏要扫 O(n) 轮,总时间退化成 O(n²)。

关键观察:遇到一个右括号时,它能不能闭合,只取决于「最近一个还没闭合的左括号」是不是同类型。这个“最近还没闭合、先来后走”的结构,正是后进先出——和「栈」天然匹配。

于是把扫描过程变成:左括号入栈;右括号和栈顶核对、配对成功就出栈;任何一步栈空或类型不匹配直接判 false;最后栈空才合法。

解法

用一个栈存放「尚未闭合的左括号」,栈顶永远是当前最内层的那个。

  1. 建立映射 右括号 → 同类型左括号。
  2. 扫描 s:遇到左括号就入栈;遇到右括号就检查「栈非空且栈顶等于映射值」,满足则出栈,否则返回 false。
  3. 扫描结束后,栈为空返回 true,非空返回 false。

以 "{[()]}" 为例(栈按“底部 → 顶部”表示):

读入动作栈(底 → 顶)
{左括号入栈{
[左括号入栈{ [
(左括号入栈{ [ (
)栈顶 ( 匹配,出栈{ [
]栈顶 [ 匹配,出栈{
}栈顶 { 匹配,出栈(空)

扫描完且栈为空,因此合法。

下图把上面 3 个步骤串成流程,并逐步演示:

20. 有效的括号(简单) 解法步骤流程图
图① 解法步骤流程图(共 3 步)。
20. 有效的括号(简单) 按步骤逐步执行的动画
动图② 按步骤依次推进(循环播放)。

C++

C++ 片段需补全 main() 函数才能运行在实训台打开 →
class Solution {
public:

🔒

本篇为付费内容

您已阅读试读部分,购买后即可解锁全文。

⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。