题目理解
我们需要判断一个字符串中的括号是否成对且顺序匹配,比如:
cpp
输入:"({[]})" → true
输入:"([)]" → false
从直觉上,这就是"遇到左括号就入栈,遇到右括号就出栈匹配 "的过程。栈这种后进先出(LIFO)的结构,天然适合这种成对匹配的问题。
解题核心思路
-
遇到左括号:入栈
-
遇到右括号:检查栈顶是否匹配
-
栈空:说明多了右括号(例如
")(") -
不匹配:说明类型不对(例如
"(]")
-
-
遍历完后,栈必须为空
如果还剩左括号没匹配上,那也是不合法的。
关于 unordered_map 的关键设计
很多题解都是这样定义:
cpp
unordered_map<char, char> mp = {{')', '('}, {']', '['}, {'}', '{'}};
这表示「右括号」是 key,「左括号」是 value。
为什么不反过来写?
因为我们匹配动作发生在遇到右括号时:
cpp
if (mp.contains(c)) { // c 是右括号
// 取出对应的左括号
if (st.empty() || st.top() != mp[c]) return false;
st.pop();
}
也就是说,我们要通过当前的右括号 c 找到它应当匹配的左括号 mp[c]。
所以 key 必须是右括号,这是逻辑上最自然的一种映射方式。
代码实现
cpp
class Solution {
// 思路: 遇到左括号进stack,遇到右边出stack
unordered_map<char, char> mp = {
{')', '('}, {']', '['}, {'}', '{'}
};
public:
bool isValid(string s) {
if (s.length() % 2) return false; // 奇数长度一定不匹配
stack<char> st;
for (char c : s) {
if (!mp.contains(c)) {
// 左括号入栈
st.push(c);
} else {
// 右括号时进行匹配
if (st.empty() || st.top() != mp[c]) {
// 注意这里 empty() 要放在前面!
return false;
}
st.pop();
}
}
return st.empty(); // 最后栈必须为空
}
};
两个易错点总结
-
奇数长度直接返回 false
因为每对括号都需要两个字符。
-
st.empty()判断要放在前面否则会先访问
st.top()导致越界错误。
小结
这个题其实是典型的**"栈 + 哈希"组合拳**:
-
哈希表解决"匹配关系";
-
栈解决"嵌套顺序";
-
顺序遍历 + 条件判断解决逻辑控制。
我认为它最大的难点不在代码,而在对操作顺序的理解反转 :
从"左括号匹配右括号",到"右括号查找左括号",这个思维变化一旦想通,后续几乎所有类似题都能一通百通。