目录
1.有效的括号
题目链接:
https://leetcode.cn/problems/valid-parentheses/https://leetcode.cn/problems/valid-parentheses/
✍有效字符: ( [ { } ] ) ( { [ ] } )
✍无效字符:{ [ ( ] ) } ( { [ } )
题解:使用栈来解决
有效字符的判断逻辑:
首先创建一个栈,首先遍历字符串,如何是左括号就将他转换为对应的右括号放入栈中,如果是右括号就和栈中已经放入的符号比较是否相同,相同就出栈,直到遍历完查看栈是否为空。
🤨特殊情况:
1.如果字符串开始就为null,我们需要在开头处判断是否为空;
2.如果字符串的右括号过多 ( ( ) ) ) ),栈中的左括号出栈出完了,此时我们需要判断栈是否为空;
3.如果左括号过多,( ( ( ( ) ) ) ,会发生在遍历完毕后导致栈中还留有元素,此时需要在遍历完成后判断栈是否为空;
代码:
class Solution {
public boolean isValid(String s) {
if(s.isEmpty()) {
return false;
}
Stack<Character> stack = new Stack();//存放左括号
for(int i = 0;i < s.length();i++) {
Character c = s.charAt(i);
//是左括号就将他转换为他的反括号放入栈中
if(c == '{') {
stack.push('}');
}else if(c == '(') {
stack.push(')');
}else if(c == '['){
stack.push(']');
}else if(stack.empty() || stack.peek() != c) {
return false;
}else {
stack.pop();
}
}
if(stack.empty()) {
return true;
}
return false;
}
}
2.逆波兰表达式求值
题目链接:力扣https://leetcode.cn/problems/evaluate-reverse-polish-notation/
什么是逆波兰表达式
首先解释一下什么是逆波兰表达式,也叫后缀表达式
正常的算式(中缀表达式):1 + 2 * 3 / 5
逆波兰表达式(后缀表达式):1 23 * 5 / +
过程解释:
首先将我们的算式加长括号来表示运算符的优先顺序,因为电脑不知道哪个运算符先算:
1 + ( (2 * 3)/ 5) , 然后我们一步一步拆分括号,根据转换公式 a + b = ab+ 来画图演示一下
题解:使用栈来解决
根据后缀表达式的特性正好符合我们的栈
🧐思路:
将表达式(数组)遍历一遍,如果是数字就将他放进栈中,如果是运算符就将栈中俩个数字拿出来和我们的运算符计算求值,然后将值放入栈中继续遍历。
画图演示:
🎃注意事项: 遇到运算符时出栈俩个元素进行计算时,注意我们的除法运算符的俩变数字不一样那么算式的值也是不一的,例如2 + 3 = 5 相等于 3 + 2 = 5,但是除法 3 / 2 和 2 / 3 这俩个式子的结果是不一样的,所以我们要将先出栈的元素放置运算符的右边,后出栈的元素放置于运算符的左方即可。
代码:
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> s = new Stack();
int sum = 0;
int x = 0;
int y = 0;
for(int i = 0;i < tokens.length;i++) {
String c = tokens[i];
if(c.equals("+")) {//为运算符时
y = s.pop();
x = s.pop();
sum = x + y;
s.push(sum);
}else if(c.equals("-")) {
y = s.pop();
x = s.pop();
sum = x - y;
s.push(sum);
}else if(c.equals("*")) {
y = s.pop();
x = s.pop();
sum = x * y;
s.push(sum);
}else if(c.equals("/")) {
y = s.pop();
x = s.pop();
sum = x / y;
s.push(sum);
}else{//为数字时
Integer a = Integer.parseInt(tokens[i]);//parseInt可以将String类字符转换为int型
s.push(a);
}
}
return s.pop();
}
}
3.栈的压入、弹出序列
题目链接:
题解:使用栈来解决
🧐思路:
首先创建一个栈,遍历我们的压入序列,将压入序列的元素放入栈中,每次遍历压入栈中的元素和我们的弹出序列相比较,如果相等,栈执行出栈操作一次,弹出序列下标往后走一步,直到遍历完我们的压入序列,最后判断栈是否为空即可。
画图描述一下思路:
代码:
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
int index = 0;
Stack<Integer> stack = new Stack<>();
for(int i = 0;i < pushA.length;i++) {
stack.push(pushA[i]);
while(!stack.empty() && stack.peek() == popA[index]) {
stack.pop();
index++;
}
}
return stack.empty();
}
}
4.最小栈
题目链接:
力扣https://leetcode.cn/problems/min-stack/description/题目描述:
题解1:额外创建一个栈来放入最小元素(最小栈和数据站同步)
🧐思路:
除了我们正常用来出栈、入栈等一系列栈的基本操作使用的的 栈 除外,我们额外创建一个最小栈,用来存放最小的元素,使我们的 getMin 可以获取到当前栈中的最小元素,
每次入栈时,不仅数据栈也要入栈,还要判断入栈的 val 值如果小于最小栈的栈顶元素我们我们也要将val值入栈到最小栈中,如果大于我们直接将最小栈的栈元素再入一份到栈顶就行了,当然前提是需要判断当前最小栈内是否为空。
出栈时,数据站和最小栈都需要出栈一个元素。
获取栈顶元素时获取 数据栈 的栈顶元素就行了
获取当前栈的最小元素时之间获取 最小栈 的栈顶元素即可
根据实例进行操作
实例中:
① 调用 MinStack() 构造方法初始化堆栈对象
② 然后 push() 入栈三个元素
③ getMin() 获取最小元素
④ pop() 出栈一个元素
⑤ top() 获取栈顶元素
⑥ getMin() 获取最小元素
题解2:额外创建一个最小栈,数据栈和最小栈不同步
🧐思路:
和题解1大致一样,区别在于栈的同步,当前我们入栈时,最小栈并不需要每次都入栈一个元素,只有在 val <= 最小栈时才进行入栈。
出栈时,最小栈的栈顶元素等于数据栈的栈顶元素时 (即数据栈需要出栈的元素) ,最小栈才进行出栈。
获取栈顶元素为数据栈顶元素
获取当前栈最元素为最小栈 栈顶元素
画图描述:
有错误的地方麻烦指出🤜🤛