跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
TypeScript大前端算法

LeetCode 20. 有效的括号:栈的典型应用

综述由AI生成讲解 LeetCode 20 题“有效的括号”,核心解法是利用栈数据结构处理括号嵌套顺序。通过遍历字符串,将左括号入栈,遇到右括号时检查栈顶是否匹配并出栈。最终判断栈是否为空以确定有效性。文章提供了 TypeScript 实现代码、逐行解析、易错点总结及复杂度分析,适合算法初学者掌握栈的基础应用。

PhpPioneer发布于 2026/3/29更新于 2026/6/229 浏览
LeetCode 20. 有效的括号:栈的典型应用

一、题目描述(清晰易懂版)

给定一个只包含三种括号的字符串 s,括号类型分别是 '('、')'、'{'、'}'、'['、']',要求判断这个字符串是否是「有效括号」。

有效括号需要同时满足 3 个条件,缺一不可:

  1. 左括号必须用「相同类型」的右括号闭合(比如 '(' 不能用 ']' 闭合);
  2. 左括号必须以「正确的顺序」闭合(比如 "({})" 有效,但 "({)}" 无效,因为括号嵌套顺序乱了);
  3. 每个右括号都有一个「对应的相同类型」的左括号(比如 ")" 单独出现一定无效)。

举几个例子帮助理解:

  • 输入 "()" → 输出 true(最简单的有效括号);
  • 输入 "()[]{}" → 输出 true(三种括号依次闭合,顺序正确);
  • 输入 "(]" → 输出 false(左括号类型与右括号不匹配);
  • 输入 "([)]" → 输出 false(嵌套顺序错误);
  • 输入 "{" → 输出 false(只有左括号,没有对应右括号)。

二、解题思路:为什么用「栈」?

这道题的核心痛点是「括号的嵌套顺序」——后出现的左括号,需要先被闭合(类似'先进后出'的逻辑),而栈这种数据结构,恰好完美匹配「先进后出」的特性。

基于栈的解题思路,拆解为 4 步:

  1. 初始化一个空栈,用于存储「未闭合的左括号」;
  2. 创建一个映射表(对象),存储「右括号对应的左括号」(比如 ')' 对应 '('),这样后续遇到右括号时,能快速找到它需要匹配的左括号;
  3. 遍历字符串的每一个字符:
    • 如果当前字符是「左括号」('('、'['、'{'),就把它压入栈中;
    • 如果当前字符是「右括号」,就检查栈是否为空,以及栈顶元素是否是它对应的左括号:
      • 如果栈为空 → 说明没有未闭合的左括号,却出现了右括号,直接返回 false;
      • 如果栈顶元素不是对应的左括号 → 匹配失败,返回 false;
      • 如果匹配成功 → 把栈顶的左括号弹出(表示这个左括号已经被成功闭合)。
  4. 遍历结束后,检查栈是否为空:
    • 栈为空 → 所有左括号都被闭合,返回 true;
    • 栈不为空 → 还有未闭合的左括号,返回 false。

三、完整解题代码(TypeScript 版)

function isValid(s: string): boolean {
    // 1. 初始化空栈,存储未闭合的左括号
    const stack = [];
    
    // 2. 建立右括号与左括号的映射关系,key 是右括号,value 是对应的左括号
    const map: { [key: string]: string } = {
        ')': '(',
        ']': '[',
        '}': '{'
    };
    
    // 3. 遍历字符串的每一个字符
    for (let i = 0; i < s.length; i++) {
        const char: string = s[i];
        
        // 判断当前字符是否是左括号,若是则压入栈中
        if (char === '(' || char === '[' || char === '{') {
            stack.push(char);
        } else {
            // 若当前是右括号,检查栈是否为空 + 栈顶是否匹配
            if (stack.length === 0 || stack[stack.length - 1] !== map[char]) {
                return false;
            }
            // 匹配成功,弹出栈顶的左括号(闭合完成)
            stack.pop();
        }
    }
    
    // 4. 遍历结束后,栈为空则所有括号都闭合,反之则有未闭合的左括号
    return stack.length === 0;
}

四、代码逐行解析(新手必看)

1. 栈的初始化

const stack = []; —— 用一个空数组模拟栈,数组的 push() 方法对应「压栈」,pop() 方法对应「出栈」,stack[stack.length - 1] 可以快速获取「栈顶元素」。

2. 映射表的作用

const map = { ')': '(', ']': '[', '}': '{' } —— 避免用复杂的 if-else 判断右括号对应的左括号。比如遇到 ')' 时,直接通过 map[char] 就能拿到它需要匹配的 '(',简洁高效。

3. 循环遍历的逻辑

遍历字符串的每一个字符,分两种情况处理:

  • 左括号:直接压栈,相当于'记录下来,等待闭合';
  • 右括号:先检查「有没有可闭合的左括号」(栈是否为空),再检查「当前右括号和栈顶左括号是否匹配」,只要有一个条件不满足,直接返回 false;匹配成功则出栈,完成一次闭合。
4. 最终判断

return stack.length === 0; —— 这一步很容易被忽略!比如输入 "{{",遍历结束后栈里还有两个左括号,此时虽然没有遇到不匹配的右括号,但依然是无效括号,所以必须判断栈是否为空。

五、易错点总结(避坑指南)

这道题看似简单,但新手很容易踩坑,整理了 3 个高频易错点:

  1. 忘记判断「栈为空」的情况:比如输入 ")",遍历到右括号时,栈是空的,此时直接返回 false,否则会执行 stack[stack.length - 1](获取空数组的 -1 索引,结果为 undefined),导致判断错误。
  2. 映射表写反键值:比如把 '(' 作为 key,')' 作为 value,这样遇到右括号时,无法通过 map[char] 拿到对应的左括号,会导致匹配失败。
  3. 遍历结束后忘记检查栈是否为空:比如输入 "{{",遍历过程中没有遇到右括号,不会返回 false,但栈不为空,此时必须返回 false,否则会误判为有效括号。

六、复杂度分析(面试加分项)

这道题的时间复杂度和空间复杂度都很优秀,面试时被问到可以从容回答:

  • 时间复杂度:O(n) —— 只遍历字符串一次,每个字符的操作(压栈、出栈、判断)都是常数时间,所以总时间和字符串长度 n 成正比。
  • 空间复杂度:O(n) —— 最坏情况下,字符串全是左括号(比如 "(((({"),此时栈需要存储所有左括号,栈的长度等于字符串长度 n;最好情况下(字符串为空或有效括号),空间复杂度可以低至 O(1)(空栈)。

七、拓展思考(进阶提升)

这道题是基础款,实际面试中可能会有变形,比如:

  1. 字符串中除了括号,还包含其他字符(比如字母、数字、符号),如何判断有效括号?(思路:遍历时分清'括号字符'和'非括号字符',只对括号字符执行上述逻辑,非括号字符直接跳过即可。)
  2. 给定有效括号字符串,计算最长有效括号子串的长度?(这是 LeetCode 32 题,难度提升,依然可以用栈解决,可作为进阶练习参考。)

目录

  1. 一、题目描述(清晰易懂版)
  2. 二、解题思路:为什么用「栈」?
  3. 三、完整解题代码(TypeScript 版)
  4. 四、代码逐行解析(新手必看)
  5. 1. 栈的初始化
  6. 2. 映射表的作用
  7. 3. 循环遍历的逻辑
  8. 4. 最终判断
  9. 五、易错点总结(避坑指南)
  10. 六、复杂度分析(面试加分项)
  11. 七、拓展思考(进阶提升)
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 从 API 到 Agent:LangChain 工程化设计详解
  • learn-claude-code 开源项目解析:AI Agent 原理与实战入门
  • OpenClaw 开源 AI 助手部署与使用完全指南
  • Shell 数组基础用法与注意事项
  • MySQL 数据库基础:数据类型与库表操作
  • Spring Boot 消息队列与异步通信实战
  • 前端函数防抖原理与实战实现
  • DeepSeek 各版本详解:从 V1 到 R1 的演进与选型指南
  • 19 个合法的黑客技术在线练习平台推荐
  • ToolkenGPT:利用工具嵌入增强大型语言模型
  • LeetCode 94. 二叉树的中序遍历(含前序、后序)
  • Windows 配置 Java 开发环境:JDK 21 + Maven + IDEA
  • C++ 标准库容器适配器:Stack、Queue 与 Priority Queue
  • Unity 面向对象编程:开闭原则详解
  • 解码 FPGA 底层架构:从触发器到时钟网络的硅视角
  • Gitee 本地项目上传与同步实战指南
  • GitHub Copilot Plan 模式核心优势与适用场景解析
  • Spring AI 集成 Anthropic Skills:Agent 工具调用实践
  • PyCharm 中 Anaconda 环境配置指南
  • 利用无监督学习为大语言模型实现信息记忆与微调

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online