力扣刷题#21-0020-有效的括号
力扣刷题#21-0020-有效的括号
题目
给定一个只包括 '(',')','{','}','[',']' 的字符串 s,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
输入: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仅负责文本修饰,综合获得以上内容。

浙公网安备 33010602011771号