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