不是吧不是吧,2025年了还有人不会括号匹配?

0 阅读5分钟

引言

大家好啊,我是前端拿破轮😁。

跟着卡哥学算法有一段时间了,通过代码随想录的学习,受益匪浅,首先向卡哥致敬🫡。

但是在学习过程中我也发现了一些问题,很多当时理解了并且AC的题目过一段时间就又忘记了,或者不能完美的写出来。根据费曼学习法,光有输入的知识掌握的是不够牢靠的,所以我决定按照代码随想录的顺序,输出自己的刷题总结和思考。同时,由于以前学习过程使用的是JavaScript,而在2025年的今天,TypeScript几乎成了必备项,所以本专题内容也将使用TypeScript,来巩固自己的TypeScript语言能力。

题目信息

有效的括号

leetcode题目链接

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左括号。

题目分析

本题是栈的应用的最经典的题目。有效括号的匹配,对于熟悉栈的同学来说此题的解法并不难。本文想要分析的关键是,为什么别人一看到这个题就会想到使用栈这种数据结构?为什么我们就想不到呢?很多同学可能会说,别人刷到过这个题呗。这确实是一个原因,而且是很重要的原因。当然也有可能根据leetcode的题目分类,这道题目被划归到栈里面,当然要使用栈了。这些都是原因,但是不是本质原因。从根本上来说,是因为本题题目中的特征符合栈后进先出(LIFO)的特点。括号进行匹配的时候,最后出现的左括号,却要最先匹配右括号,这不就是典型的栈的特征吗。所以掌握了根本原因后,以后我们在遇到没有见过的题目时,才能判断出解题方法。

本题整体上的思路就是,从左往右遍历括号字符串,如果是左括号,则入栈,如果是右括号,则将栈顶元素弹出,判断两者是否匹配。如果不匹配,直接剪枝返回false。如果匹配,则接着往后扫描。直到最后,判断辅助栈是否为空。如果栈非空,则说明有多余的左括号,不匹配。否则匹配。

这里面除了整体上使用栈的思路外,还有两个点需要注意。

  1. 如何判断一个字符串是左括号还是有括号

  2. 如何判断两个括号是否匹配

对于1,简单做法可以直接用相等符===和逻辑运算符||来进行判断。比如if(c === '{' || c === '[' || c === '(')来进行判断,也可以写一个Set哈希表来判断,比如const set = new Set('{', '[', '('),然后利用APIset.has()来判断,如果在set中,就是左括号。由于题目说到整个字符串只有左右括号,所以如果不在set中,一定是右括号。

对于2,可以针对不同的情况分别进行判断,比如if(c === '}')的情况下再判断栈顶弹出的元素是不是},但是这样就会导致if-else嵌套过深,导致圈复杂度过高,可读性也会降低。另一种方式是使用一个对象,会二维数组,保存左右括号之间的对应关系。

最合理的方案是使用哈希表Map,可以同时解决1和2的问题。因为Map拥有Set的功能,而且还能存储键值对,直接一步解决了两个问题。具体可以看题解部分。

题解

function isValid(s: string): boolean {
    // map对象存储映射关系
    const map = new Map([
        ['}', '{'],
        [']', '['],
        [')', '(']
    ]);

    // 辅助栈
    const stack = [];
    
    // 遍历字符串
    for (let c of s) {
        // 如果不在map中,一定是左括号,直接入栈
        if (!map.has(c)) {
            stack.push(c);
        } else {
            // 如果c在map中,说明c是右括号,将栈顶元素弹出
            const left = stack.pop();
            // 判断栈顶元素是不是当前右括号匹配的左括号,不匹配直接剪枝
            if (left !== map.get(c)) return false;
        }
    }
    // 最后结束后要根据栈是否为空
    return stack.length === 0;
};

时间复杂度: O(n)O(n), 只需要遍历一次字符串。

空间复杂度: O(n)O(n),需要问题规模的辅助栈,还有常数级别的map对象空间。总体是O(n)O(n)

总结

本题是栈最经典的题目,因为括号匹配的后进先出的特点和栈完美吻合。在处理过程中还要用到map对象来存储映射关系。以及最后一定要记得判断辅助栈是否为空。这一点很容易被忽略。很多同学遍历完发现都匹配就直接返回true,没有考虑到左括号可能多余的情况。

好了,这篇文章就到这里啦,如果对您有所帮助,欢迎点赞,收藏,分享👍👍👍。您的认可是我更新的最大动力。由于笔者水平有限,难免有疏漏不足之处,欢迎各位大佬评论区指正。

往期推荐✨✨✨

我是前端拿破轮,关注我,一起学习前端知识,我们下期见!