思路
栈与队列相关的题目做的比较少,还真想不到用栈来解决,本题最核心的思路点在于怎么去确定两个括号是否能匹配,解决思路为遇到 左括号 就把相应的右括号放进去,当遇到右括号时,再对栈里的内容进行弹出匹配。
接下来是如何判断所有括号无法匹配,有以下三种情况
- 左括号多余
- 右括号多余
- 左右括号不多余但是无法匹配
代码实现
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
char c;
for (int i = 0; i < s.length(); i++) {
c = s.charAt(i);
if (c == '('){
stack.push(')');
} else if (c == '[') {
stack.push(']');
} else if (c == '{') {
stack.push('}');
}
//以上的 if 条件实现了所有左括号的入栈
//接下来判断 是否为空或者右括号与栈顶的左括号是都匹配
else if (stack.isEmpty() || stack.peek() != c){
return false;
}else {
stack.pop();
}
}
//所有的右括号都判断完了 这是 看栈是否为空
return stack.isEmpty();
}
L1047. 删除字符串中的所有相邻重复项
思路
要确保相邻的两个字母不一样,那么如果用栈的思想,在每一次压入一个新的元素入栈的时候,判断此时将要压入的元素和栈顶的元素是否相同,如果相同则将栈顶元素弹出,同时将当前元素“抛弃”。
那么什么时候将当前字母压入到栈里
- 目前栈是空的
- 目前字母和栈顶字母不相同
代码实现
写代码的时候才发现如果这里用栈的话,后面弹出之后,数组是反的,还要进行翻转。所以实际应该是用队列。
补充: 这样写其实就不需要翻转了
while (!deque.isEmpty()) {
str = deque.pop() + str;
}
用栈实现(需要翻转)
public String removeDuplicates(String s) {
Stack<Character> chars = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
//什么时候压入? 目前栈是空的 目前字母和栈顶字母不相同
if (chars.empty() || chars.peek() != ch) {
chars.push(ch);
} else {
chars.pop();
}
}
StringBuilder stringBuilder = new StringBuilder();
while (!chars.empty()){
stringBuilder.append(chars.pop());
}
stringBuilder.reverse();
return stringBuilder.toString();
}
栈的一个注意点
当栈为空的时候 empty方法的返回值是true 所以以上需求中应该用的是 !char.empty()
用队列实现
首先明确java中new的方式
Deque<String> animal1 = new ArrayDeque<>();
Deque<String> animal2 = new LinkedList<>();
-
底层数据结构:
ArrayDeque
:使用可调整大小的数组来存储元素,因此其操作效率更高,特别是在随机访问元素和尾部添加/删除元素的情况下。LinkedList
:使用双向链表来存储元素,这使得在列表中间插入和删除元素的操作更为高效。
-
性能特点:
ArrayDeque
在大多数情况下具有更好的性能,因为它的底层数组支持随机访问,因此可以在O(1)时间复杂度内对队列的头部和尾部进行操作。LinkedList
对于频繁的插入和删除操作,尤其是在列表中间,性能可能会更好,因为链表的结构使得插入和删除操作的时间复杂度为O(1)。
-
内存占用:
ArrayDeque
在一般情况下会占用更少的内存,因为它使用的是一个连续的数组。LinkedList
通常会占用更多的内存,因为除了存储元素值之外,还需要存储每个元素的指向前后元素的指针。
-
功能特性:
- 由于
ArrayDeque
基于数组,它不支持元素的空值(null);而LinkedList
可以存储空值。 ArrayDeque
不支持在中间位置的O(1)时间内的插入和删除操作。
- 由于
L0150. 逆波兰表达式求值
思路
对于模拟题 明确规则之后就比较容易写出代码。
那么这里的规则:从左到右对表达式进行遍历,如果遇到数字就进栈,如果是符号就取出栈顶的两个元素进行运算,然后把运算的结果压入栈。
代码实现
需要注意的点时 减法和除法运算需要分前后
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (String str : tokens) {
if (str.equals("+")) {
stack.push(stack.pop() + stack.pop());
} else if (str.equals("*")) {
stack.push(stack.pop() * stack.pop());
} else if (str.equals("-")) {
Integer temp1 = stack.pop();
Integer temp2 = stack.pop();
stack.push(temp2 - temp1);
} else if (str.equals("/")) {
Integer temp1 = stack.pop();
Integer temp2 = stack.pop();
stack.push(temp2 / temp1);
}else {
stack.push(Integer.valueOf(str));
}
}
return stack.pop();
}
L1047. 删除字符串中的所有相邻重复项
思路
当前字母与栈顶相同时,扔掉当前字母并且弹出栈顶
值得学习的思路是在进行字符串连接时,“倒着拼接”可以避免最后的reverse。
代码实现
public static String removeDuplicates(String s) {
Deque<Character> deque = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (deque.isEmpty() || ch != deque.peek()) {
deque.push(ch);
} else {
deque.pop();
}
}
String res = "";
while (!deque.isEmpty()) {
res = deque.pop() + res;
}
return res;
// StringBuilder stringBuilder = new StringBuilder();
// while (!deque.isEmpty()){
// stringBuilder.append(deque.pop());
// }
// return stringBuilder.reverse().toString();
}