leetcode算法练习
20. 有效的口号
题目链接
不匹配的场景:
- ( [ { } ] () 左边括号多余
- [ { ( } } ] 括号类型不匹配
- [ { } ] ( ) ) ) 右边括号多余
思路:
剪支条件:如果数量不是偶数 可以直接判断无效
- 遇到左括号 就把对应的右括号加入到栈里 因为之后弹出匹配可以直接和元素进行比较
例如:( [ { } ] () 就是先入栈) ] } 而后出栈和} ] 依次匹配 再将)入栈 最后因为)消除一个) 栈中还剩余一个) 说明是无效的 - 字符串的括号和栈中不匹配 说明是无效的
- 字符串还没有遍历完 栈就空了 说明右边括号多余了 是无效的
class Solution {
public boolean isValid(String s) {
Deque<Character> deque = new LinkedList<>();
char ch;
for (int i = 0; i < s.length(); i++) {
ch = s.charAt(i);
//碰到左括号,就把相应的右括号入栈
if (ch == '(') {
deque.push(')');
}else if (ch == '{') {
deque.push('}');
}else if (ch == '[') {
deque.push(']');
} else if (deque.isEmpty() || deque.peek() != ch) {
// 要先判断是否为空 否则取stack.peek是会异常的
return false;
}else {
//如果是右括号判断是否和栈顶元素匹配
deque.pop();
}
}
// 第一种情况也处理了 当字符串遍历完 栈还为空 说明左括号是多的 是无效的
// 如果栈为空 那么说明就是有效的
return deque.isEmpty();
}
}
1047. 删除字符串中的所有相邻重复项
题目链接
栈特别适用于相邻元素/重复项/括号匹配
思路:
- 栈用来存放遍历过的元素 每遍历一个元素都要去栈中询问是否之前有遍历到过
例如:abbaca ——aaca——ca
- a先入栈——栈内a
- 遍历到b b和栈内a不相等 b入栈——栈内(栈顶)ba(栈底)
- 遍历到b 发现栈顶为b 故把栈顶的b弹出——栈内a
- 遍历到a 发现栈内a 故把栈顶的a弹出——栈为空
- 遍历到c c存入栈中——栈为c
- 遍历到a a和栈顶c不相同 存入栈中——栈为ac
- 最后把栈内数据输出 转成字符串——可以直接用字符串来模拟栈 可以字符串的头部作为栈的尾部 字符串的尾部作为栈的头部 这样就可以不用反转了
class Solution {
public String removeDuplicates(String S) {
// ArrayDeque会比LinkedList在除了删除元素这一点外会快一点
ArrayDeque<Character> deque = new ArrayDeque<>();
char ch;
// 循环遍历字符串
for (int i = 0; i < S.length(); i++) {
// 获取单个字母
ch = S.charAt(i);
// 如果栈为空或栈顶的元素和当前遍历的元素不同 直接存入
if (deque.isEmpty() || deque.peek() != ch) {
deque.push(ch);
} else {
// 弹出栈顶元素
deque.pop();
}
}
String str = "";
// 剩余的元素即为不重复的元素
while (!deque.isEmpty()) {
str = deque.pop() + str;
}
return str;
}
}
150. 逆波兰表达式求值
题目链接
逆波兰表达式其实是一种后缀表达式
例如:(1+2)*(3+4)转换成二叉树 如图
后序:12+34+×
中序:1+2×3+4(看着舒服 但是正确计算得加括号 (1+2)×(3+4))但后序表达式不需要——如何处理得到结果?利用栈
思路:
- 遇到数字就加入栈 遇见操作符就从栈中取出数字 进行运算再存入栈中
例如:(1+2)*(3+4)转为12+34+×
- 数字1 入栈——栈内1
- 数字2 入栈——栈内(栈顶)2 1(栈底)
- 操作符+ 取出2 1 运算得到3 再放入栈——栈内3
- 数字3 入栈——栈内(栈顶)3 3(栈底)
- 数字4 入栈——栈内(栈顶)4 3 3(栈底)
- 操作符+ 取出4 3 运算得到7 再放入栈——栈内(栈顶)7 3(栈底)
- 操作符× 取出7 3 运算得到21 再放入栈——栈内21(结果也放入栈 可以统一规则 免得再做特殊处理)
- 结果就是21
class Solution {
public int evalRPN(String[] tokens) {
// 创建栈
Deque<Integer> stack = new LinkedList();
// 遍历字符串
for (String s : tokens) {
// 遇见操作符 去元素pop 存元素push
if ("+".equals(s)) { // leetcode 内置jdk的问题,不能使用==判断字符串是否相等
stack.push(stack.pop() + stack.pop()); // 注意 - 和/ 需要特殊处理
} else if ("-".equals(s)) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(s)) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(s)) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
// 把数字放入栈中 要转为int类型
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}