有效的括号
题目描述
给定一个只包含 '(', ')', '{', '}', '[', ']' 的字符串,判断是否每个左括号都能被正确的右括号闭合,并且顺序正确。
例如:
输入 | 输出 | 解释 |
---|---|---|
"()" |
true |
成对 |
"()[]{}" |
true |
成对,顺序正确 |
"(]" |
false |
括号类型不匹配 |
"([)]" |
false |
顺序不正确 |
"{[]}" |
true |
成对嵌套 |
解题思路
这道题是使用栈解决的经典问题。
为什么可以用栈来做?
栈是一种后进先出(LIFO)的数据结构,非常适合处理成对出现且嵌套结构的问题。
想象如下字符串:
"{ [ ( ) ] }"
从左往右处理:
- 遇到左括号时就压入栈。
- 遇到右括号时,从栈顶取出最近的左括号,检查是否与当前右括号匹配。
- 匹配则继续,不匹配则返回 false。
以字符串 "{(){[]}}" 为例: 步骤如下:
i | 当前字符 | 栈操作 | 栈状态 | 说明 |
---|---|---|---|---|
0 | { |
入栈 | { |
左括号入栈 |
1 | ( |
入栈 | { ( |
左括号入栈 |
2 | ) |
匹配 & 出栈 | { |
) ↔ ( 成功匹配 |
3 | { |
入栈 | { { |
左括号入栈 |
4 | [ |
入栈 | { { [ |
左括号入栈 |
5 | ] |
匹配 & 出栈 | { { |
] ↔ [ 成功匹配 |
6 | } |
匹配 & 出栈 | { |
} ↔ { 成功匹配 |
7 | } |
匹配 & 出栈 | 空 | } ↔ { 成功匹配 |
C++ 代码实现
cpp
bool isValid(string s) {
stack<char> stk;
for (char ch : s) {
// 左括号,压入栈
if (ch == '(' || ch == '{' || ch == '[')
stk.push(ch);
else {
// 遇到右括号,栈必须非空
if (stk.empty()) return false;
char top = stk.top();
// 判断是否匹配
if ((ch == ')' && top != '(') ||
(ch == '}' && top != '{') ||
(ch == ']' && top != '['))
return false;
stk.pop(); // 匹配成功,弹出
}
}
// 如果所有括号都匹配,栈应为空
return stk.empty();
}
复杂度分析
时间复杂度:O(n),只遍历一次字符串
空间复杂度:O(n),最坏情况下栈中存放所有左括号
代码优化
优化一:
如果字符串长度是奇数(n % 2 == 1),直接返回 false,因为括号必须成对出现,不可能匹配成功。
cpp
int n = s.size();
if (n % 2 == 1) {
return false;
}
优化二:
定义一个哈希表 pairs,用于映射每个右括号对应的左括号。
cpp
unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};
用哈希表 unordered_map 映射右括号对应的左括号,方便查找。而且可以提高代码的可扩展性,逻辑更清晰。
C++ 代码实现
cpp
class Solution {
public:
// 判断输入字符串中的括号是否成对匹配
bool isValid(string s) {
int n = s.size();
// 若长度为奇数,不可能完全配对,直接返回 false
if (n % 2 == 1) {
return false;
}
// 定义右括号到左括号的映射关系
unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};
stack<char> stk; // 用栈来存储尚未匹配的左括号
// 遍历字符串中的每一个字符
for (char ch : s) {
// 如果是右括号
if (pairs.count(ch)) {
// 栈为空或栈顶不是对应的左括号,说明匹配失败
if (stk.empty() || stk.top() != pairs[ch]) {
return false;
}
stk.pop(); // 匹配成功,弹出左括号
} else {
// 是左括号,入栈
stk.push(ch);
}
}
// 最终栈为空,说明所有括号都匹配成功
return stk.empty();
}
};