力扣刷题#21-0020-有效的括号

力扣刷题#21-0020-有效的括号

题目

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

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。
输入:s = "()"
输出:true
输入:s = "()[]{}"
输出:true
输入:s = "(]"
输出:false
输入:s = "([)]"
输出:false

我的思路:逆波兰式原理

看到括号匹配,我第一反应是逆波兰表达式中的栈用法——遇到操作数就压栈,遇到运算符就弹栈计算。

括号匹配也是同理:

遇到左括号 → 压入栈中("我没配对,等着")
遇到右括号 → 从栈顶拿一个出来配对:
  - 配对成功 → 弹出,继续
  - 配对失败 → 直接 false

就像一个"括号停车场"——进的括号先停最里面,出去的括号必须和最里面的那个匹配。先进后出,天然是栈的结构。

生活化类比

图书馆存包柜——你把书包(左括号)放进柜子,走的时候凭钥匙(右括号)开柜取出。如果钥匙对不上锁,要么你拿错了钥匙(括号类型不对),要么柜子是空的(右括号多了),要么你忘了开柜(左括号多了)。


我的 AC 代码

class Solution {
public:
    bool isValid(string s) {
        stack<char> st;
        for (char c : s) {
            if (c == '(' || c == '{' || c == '[') {
                st.push(c);
            } else {
                if (st.empty()) return false;
                if (st.top() == '(' && c == ')')
                    st.pop();
                else if (st.top() == '[' && c == ']')
                    st.pop();
                else if (st.top() == '{' && c == '}')
                    st.pop();
                else return false;
            }
        }
        if (st.empty()) return true;
        return false;
    }
};

代码逐步解析

第 4-5 行:遍历每个字符

for (char c : s) {

逐个检查每个括号。不跳步,顺序很重要——括号的顺序决定了是否合法。

第 6-8 行:左括号压栈

if (c == '(' || c == '{' || c == '[') {
    st.push(c);
}

遇到左括号,不管三七二十一,先压入栈。它等着后面某个右括号来和它配对。

第 10 行:右括号到达,先判栈空

if (st.empty()) return false;

这是关键保护——如果当前是右括号但栈已经空了,说明右括号比左括号多,直接 false。比如 ")""())"

这行不能放在外层 if 条件里,因为左括号压栈时栈空是合法的,只有右括号遇到空栈才是非法。

第 11-16 行:三种配对判断,用 else if 串联

if (st.top() == '(' && c == ')')
    st.pop();
else if (st.top() == '[' && c == ']')
    st.pop();
else if (st.top() == '{' && c == '}')
    st.pop();
else return false;

这里的关键写法:三个判断用 else if 串联,不是三个独立 if

  • else if:排他性。第一个匹配了就结束,不继续判后面。
  • 独立 if:非排他。第一个匹配并 pop 后,第二个 if 可能对一个已经变了的栈顶做判断。

最后 else 兜底——都不匹配,说明括号类型对不上(比如栈顶 ( 但遇到 ]),返回 false

第 19-20 行:遍历结束后的终判

if (st.empty()) return true;
return false;

循环走完后,如果栈不空,说明左括号多了(有括号没配对,一直留在栈里)。比如 "((" → 栈里剩两个 ( → 返回 false

这里必须有 return false 兜底——不能只写 if(st.empty())return true; 就结束。编译器不做逻辑推演,它看到 if 后面没有 else 或额外的 return 就会报 control reaches end of non-void function


踩坑记录

坑 :函数末尾缺少 return false(编译报错)

// ❌ 第三版
if (st.empty()) return true;
}   // ← 如果栈不空,这里没有 return!

报错control reaches end of non-void function

原因:编译器不做逻辑推演。它看到 if(st.empty()) return true; 之后什么都没有——从语法结构上看,如果 st.empty() 为 false(栈不空),函数就没有返回值。即使你认为"栈不空的情况在逻辑上不会发生",编译器也不认。

修复

if (st.empty()) return true;
return false;     // ← 必须补这行,告诉编译器"不空我就返回 false"

优化分析

优化项 说明
奇数长度预处理 if(s.size()%2) return false; 可提前排除奇数长度的非法输入
哈希表映射 unordered_map<char,char> 存右→左映射,避免三个 if-else-if
栈用 string 模拟 string stk; stk.push_back(c); stk.pop_back(); 少一个头文件

复杂度分析

维度 说明
时间复杂度 O(n) 每个字符入栈出栈各一次
空间复杂度 O(n) 最坏全左括号,栈存 n 个字符

本文档由 AI 辅助生成,作者提供问题,思路和代码,AI仅负责文本修饰,综合获得以上内容。

posted @ 2026-06-26 16:42  STA_running  阅读(9)  评论(0)    收藏  举报