020-有效的括号
返回给定一个只包括
'(',')','{','}','[',']'的字符串s,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
思路:用栈匹配成对括号
- 左括号:入栈,等待后面出现与之匹配的右括号。
- 右括号:必须与「当前栈顶的左括号」匹配,否则字符串无效。
另外有两个剪枝:
- 字符串长度如果是奇数,肯定不可能全部成对闭合,直接返回
false。 - 遍历结束后,如果栈还不为空,说明还有多余的左括号,也是不合法的。
代码实现
class Solution {
public boolean isValid(String s) {
// 计算字符串长度
int len = s.length();
// 如果字符串长度为奇数,必然有一个不能闭合
if (len % 2 == 1) {
return false;
}
// 左右括号成对,适合用 map 数据结构来存储
Map<Character, Character> map = new HashMap<>();
map.put('(', ')');
map.put('{', '}');
map.put('[', ']');
// 用栈来存储左括号,栈顶就应该有最近的右括号匹配
Deque<Character> stack = new ArrayDeque<>();
// 遍历整个字符串
for (int i = 0; i < len; i++) {
// 获取当前字符
char ch = s.charAt(i);
// 当前字符属于左括号
if (map.containsKey(ch)) {
// 入栈
stack.push(ch);
} else {
// 当前字符属于右括号,进行匹配
// 栈为空或者当前字符和栈顶括号不匹配,说明不符合,直接返回 false
if (stack.isEmpty() || ch != map.get(stack.peek())) {
return false;
}
// 成功匹配一对,将当前栈顶元素弹出
stack.pop();
}
}
// 如果栈中有剩余那么不符合要求,为空说明匹配完成并且没有剩余
return stack.isEmpty();
}
}
为什么用 Deque(ArrayDeque),而不直接用 Stack?
Stack是老设计(遗留类)Stack继承自Vector,属于早期 Java 集合框架产物。Vector的很多方法是同步的(synchronized),设计上偏「线程安全容器」,解算法题并不需要。
Stack的同步开销通常是多余的Stack的push/pop/peek都带同步,属于没有必要的成本。
ArrayDeque当栈更快、更省内存ArrayDeque用数组实现,连续内存,局部性更好,性能通常更好。
在 LeetCode 等算法题场景下,推荐:
- 接口使用
Deque<E>(更通用,既可以当栈也可以当队列) - 实现类使用
ArrayDeque<E>作为栈的替代。