Java 实现括号匹配:栈的应用与优化
在编程中,括号匹配问题是一个常见的题目,尤其在编写表达式解析器时,正确地识别和匹配括号是至关重要的。本文将讨论如何使用 Java 实现括号匹配,并展示如何通过使用不同的栈实现进行优化。
题目描述
给定一个只包含括号的字符串,判断字符串中的括号是否有效。有效的括号需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
例如:
"()"
和"()[]{}"
是有效的括号字符串。"(]"
和"([)]"
是无效的括号字符串。
基础实现:使用 Stack
类
Java 提供了 Stack
类来支持栈的基本操作。以下代码展示了如何使用 Stack
类来实现括号匹配。
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
// 如果字符是左括号(小括号、大括号或方括号)
if (c == '(' || c == '{' || c == '[') {
// 将左括号压入栈中
stack.push(c);
} else {
// 如果栈为空,则返回false,表示括号不匹配
if (stack.isEmpty()) return false;
// 弹出栈顶元素
char top = stack.pop();
// 判断右括号与栈顶元素是否匹配
if (c == ')' && top != '(' ||
c == '}' && top != '{' ||
c == ']' && top != '[') return false;
}
}
// 如果栈为空,表示所有括号都匹配成功,返回true;否则返回false
return stack.isEmpty();
}
代码分析
- 使用栈存储左括号:当遇到左括号时,将其压入栈中。
- 匹配右括号:当遇到右括号时,检查栈是否为空。如果为空,则说明没有对应的左括号,返回
false
。否则,弹出栈顶元素并检查其是否与当前的右括号匹配。 - 最终判断:遍历完成后,如果栈为空,则说明所有的括号都已匹配,返回
true
;否则返回false
。
优化实现:使用 ArrayDeque
代替 Stack
虽然 Stack
是直接支持栈操作的类,但在性能上可以使用 ArrayDeque
来替代它。ArrayDeque
是一个双端队列,但也可以用作栈,且比 Stack
更高效。
使用 ArrayDeque
的代码实现
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
// 如果字符是左括号(小括号、大括号或方括号)
if (c == '(' || c == '{' || c == '[') {
// 将左括号压入栈中
stack.push(c);
} else {
// 如果栈为空,则返回false,表示括号不匹配
if (stack.isEmpty()) return false;
// 弹出栈顶元素
char top = stack.pop();
// 判断右括号与栈顶元素是否匹配
if (c == ')' && top != '(' ||
c == '}' && top != '{' ||
c == ']' && top != '[') return false;
}
}
// 如果栈为空,表示所有括号都匹配成功,返回true;否则返回false
return stack.isEmpty();
}
优化效果
ArrayDeque
提供了比 Stack
更好的性能表现,尤其在频繁的压入和弹出操作下。虽然两者在 API 上看似相同,但在底层实现上,ArrayDeque
基于数组而非同步的栈,因而避免了线程安全带来的额外开销。
总结
本文介绍了如何使用 Java 的 Stack
类和 ArrayDeque
类来实现括号匹配,并解释了其中的代码逻辑。通过使用 ArrayDeque
替代 Stack
,我们可以进一步提升代码的性能。
对于初学者来说,掌握这些基础的数据结构和算法是至关重要的。希望这篇博客能够帮助你理解如何处理括号匹配问题,以及如何在 Java 中有效地使用栈来解决类似问题。