栈-有效的括号

第一步:想什么数据结构适合解决这个问题?

我先想:括号的闭合是「后进先出 」的顺序 ------ 最后出现的左括号,必须最先被闭合。比如 {[()]}

  • 左括号顺序:{[(
  • 右括号顺序:)]}
  • 正好是「最后进来的 ( 第一个出去」,完美符合 ** 栈(Stack)** 的特性!

那栈的作用就明确了:

  • 遇到左括号:压入栈中(存起来,等对应的右括号来匹配)
  • 遇到右括号:必须和栈顶的左括号匹配,匹配成功就弹出栈顶;匹配失败直接返回无效

第二步:先想边界条件,再写核心逻辑

1. 最容易想到的优化:长度为奇数直接返回 false

括号必须成对出现,所以如果字符串长度是奇数,100% 无效,直接 return false,不用再遍历了,省时间。对应代码第 4-6 行:

java 复制代码
if (n % 2 == 1) {
    return false;
}

2. 怎么快速判断右括号和左括号是否匹配?

我需要一个映射:右括号 → 对应的左括号,这样遇到右括号时,直接查它该匹配哪个左括号,不用写一堆 if-else。比如:

  • )(
  • ][
  • }{用 HashMap 存这个映射最方便,对应代码第 8-13 行:
java 复制代码
Map<Character, Character> pairs = new HashMap<Character, Character>() {{
    put(')', '(');
    put(']', '[');
    put('}', '{');
}};

3. 核心遍历逻辑

我要遍历字符串的每一个字符 ch

情况 1:ch 是右括号(在 HashMap 的 key 里)

  • 先判断:如果栈是空的(说明没有左括号和它匹配,比如第一个字符就是 )),或者栈顶元素不是对应的左括号(比如栈顶是 [,当前是 )),直接 return false
  • 如果匹配成功:把栈顶的左括号弹出(表示这对括号闭合了)

情况 2:ch 是左括号(不在 HashMap 的 key 里)

  • 直接压入栈中,等后面的右括号来匹配

对应代码第 15-28 行:

java 复制代码
Deque<Character> stack = new LinkedList<Character>();
for (int i = 0; i < n; i++) {
    char ch = s.charAt(i);
    // 若当前字符为 右括号
    if (pairs.containsKey(ch)) {
        // 若栈内为空 或 栈顶元素(左括号) 不是与当前右括号匹配的类型,直接返回false
        if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
            return false;
        }
        // 匹配,则弹出栈顶元素(左括号)
        stack.pop();
    } else {
        // 若当前字符不是右括号,则加入栈中
        stack.push(ch);
    }
}

补充:为什么用 Deque 而不是 Stack 类?Java 里的 Stack 是遗留类,继承了 Vector,性能和设计都不好,官方推荐用 Deque(双端队列)的 LinkedList 实现来模拟栈,push() 对应入栈,pop() 对应出栈,peek() 对应取栈顶,完全满足需求。

4. 遍历完之后,还要判断什么?

遍历完所有字符,不代表一定有效!比如 (( 这种情况:两个左括号,遍历完栈里还有两个元素,说明左括号多了,没有对应的右括号闭合。所以最后必须判断:栈是否为空?

  • 空:所有左括号都被正确闭合,返回 true
  • 非空:有左括号没闭合,返回 false

对应代码第 30-32 行:

java 复制代码
return stack.isEmpty();

第三步:用例子验证逻辑

例子 1:{[]}(有效)

  • 长度 4(偶数),继续
  • 遍历:
    1. {:左括号,入栈 → 栈:[{]
    2. [:左括号,入栈 → 栈:[{, []
    3. ]:右括号,查映射对应 [,栈顶是 [,匹配,弹出 → 栈:[{]
    4. }:右括号,查映射对应 {,栈顶是 {,匹配,弹出 → 栈:空
  • 遍历完栈空,返回 true ✅

例子 2:([)](无效)

  • 长度 4(偶数),继续
  • 遍历:
    1. (:入栈 → 栈:[(]
    2. [:入栈 → 栈:[(, []
    3. ):右括号,查映射对应 (,栈顶是 [,不匹配 → 直接返回 false ❌

例子 3:(((无效)

  • 长度 2(偶数),继续
  • 遍历:两个 ( 都入栈 → 栈:[(, (]
  • 遍历完栈非空,返回 false ❌

例子 4:)(无效)

  • 长度 1(奇数),直接返回 false ❌

完整代码

java 复制代码
class Solution {
    public boolean isValid(String s) {
        int n = s.length();
        //数组长度为奇数直接返回false
        if (n % 2 == 1) {
            return false;
        }
        // 哈希表的键为右括号,值为相同类型的左括号,用于快速判断括号是否匹配
        Map<Character, Character> pairs = new HashMap<Character, Character>() {{
            put(')', '(');
            put(']', '[');
            put('}', '{');
        }};
        Deque<Character> stack = new LinkedList<Character>();
        for (int i = 0; i < n; i++) {
            char ch = s.charAt(i);
            // 若当前字符为 右括号
            if (pairs.containsKey(ch)) {
                // 若栈内为空 或 栈顶元素(左括号) 不是与当前右括号匹配的类型,直接返回false
                if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
                    return false;
                }
                // 匹配,则弹出栈顶元素(左括号)
                stack.pop();
            } else {
                // 若当前字符不是右括号,则加入栈中
                stack.push(ch);
            }
        }
        // 遍历完成,若栈内为空,则返回true,若栈内还剩余元素,则说明不符合返回false
        return stack.isEmpty();
    }
}

复杂度分析

  • 时间复杂度:O (n),只遍历了一次字符串,每个字符入栈 / 出栈最多一次
  • 空间复杂度:O (n),最坏情况(全是左括号)栈里存 n 个元素
相关推荐
再一次等风来2 小时前
近场声全息(NAH)仿真实现:从阵列实值信号到波数域重建
算法·matlab·信号处理·近场声全息·nah
汀、人工智能2 小时前
16 - 高级特性
数据结构·算法·数据库架构·图论·16 - 高级特性
大熊背2 小时前
利用ISP离线模式进行分块LSC校正的方法
人工智能·算法·机器学习
Java面试题总结2 小时前
Spring - Bean 生命周期
java·spring·rpc
硅基诗人2 小时前
每日一道面试题 10:synchronized 与 ReentrantLock 的核心区别及生产环境如何选型?
java
014-code2 小时前
String.intern() 到底干了什么
java·开发语言·面试
XWalnut2 小时前
LeetCode刷题 day4
算法·leetcode·职场和发展
蒸汽求职3 小时前
机器人软件工程(Robotics SDE):特斯拉Optimus落地引发的嵌入式C++与感知算法人才抢夺战
大数据·c++·算法·职场和发展·机器人·求职招聘·ai-native
摇滚侠3 小时前
JAVA 项目教程《苍穹外卖-12》,微信小程序项目,前后端分离,从开发到部署
java·开发语言·vue.js·node.js