目录
最小栈
1.题目要求:
设计一个支持 push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
实现
MinStack
类:
MinStack()
初始化堆栈对象。void push(int val)
将元素val推入堆栈。void pop()
删除堆栈顶部的元素。int top()
获取堆栈顶部的元素。int getMin()
获取堆栈中的最小元素。
示例 1:
输入: ["MinStack","push","push","push","getMin","pop","top","getMin"] [[],[-2],[0],[-3],[],[],[],[]] 输出: [null,null,null,null,-3,null,0,-2] 解释: MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); --> 返回 -3. minStack.pop(); minStack.top(); --> 返回 0. minStack.getMin(); --> 返回 -2.
提示:
-231 <= val <= 231 - 1
pop
、top
和getMin
操作总是在 非空栈 上调用push
,pop
,top
, andgetMin
最多被调用3 * 104
次
2.解题思路:
在栈的类中创建一个辅助栈,辅助栈中的元素个数与具体栈保持一致,辅助栈专门用来保存当前栈中的最小值,第一次入栈不需要判断,两个栈中存放相同的元素,第二次及以后需要判断,如果入栈的元素比辅助栈的栈顶元素小,那么辅助栈存放小的元素,如果比辅助栈栈顶元素大,那么把辅助栈栈顶元素再入栈一次即可
3.代码展示:
class MinStack {
//存放具体元素
private int [] data1;
//存放最小值,和上面的栈元素个数保持一致
private int [] data2;
private int size;
public MinStack() {
data1 = new int[100];
data2 = new int[100];
}
public void isfull(){
data1 = Arrays.copyOf(data1,size<<1);
data2 = Arrays.copyOf(data2,size<<1);
}
public void push(int val) {
if(isEmpty()){
data1[size] = val;
data2[size] = val;
size++;
return;
}
//栈满扩充
if(size == data1.length){
isfull();
}
data1[size] = val;
if(val < data2[size-1]){
data2[size] = val;
}else{
data2[size] = data2[size-1];
}
size++;
}
public void pop() {
size--;
}
public int top() {
return data1[size-1];
}
public int getMin() {
return data2[size-1];
}
public boolean isEmpty(){
return size == 0;
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
栈的压入、弹出序列
1.题目要求:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
示例 1:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1] 输出:true 解释:我们可以按以下顺序执行: push(1), push(2), push(3), push(4), pop() -> 4, push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:
输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2] 输出:false 解释:1 不能在 2 之前弹出。
提示:
0 <= pushed.length == popped.length <= 1000
0 <= pushed[i], popped[i] < 1000
pushed
是popped
的排列。
2.解题思路:
考虑借用一个辅助栈 stack ,模拟 压入 / 弹出操作的排列。根据是否模拟成功,即可得到结果。
入栈操作: 按照压栈序列的顺序执行。
出栈操作: 每次入栈后,循环判断 “栈顶元素 === 弹出序列的当前元素” 是否成立,将符合弹出序列顺序的栈顶元素全部弹出。
由于题目规定 栈的所有数字均不相等 ,因此在循环入栈中,每个元素出栈的位置的可能性是唯一的(若有重复数字,则具有多个可出栈的位置)。因而,在遇到 “栈顶元素 === 弹出序列的当前元素” 就应立即执行出栈。
3.代码展示:
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
//按顺序入栈,与第二个元素相同,
int i= 0;
Stack<Integer> stack = new Stack<>();
for(int temp:pushed){
stack.push(temp);
while(!stack.isEmpty() && stack.peek() == popped[i]){
stack.pop();
i++;
}
}
return stack.isEmpty();
}
}
有效的括号
1.题目要求
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()" 输出:true
示例 2:
输入:s = "()[]{}" 输出:true
示例 3:
输入:s = "(]" 输出:false
提示:
1 <= s.length <= 104
s
仅由括号'()[]{}'
组成
2.解题思路
遍历字符串如果 c 是左括号,则入栈 push;
否则判断其对应关系,若 stack 栈顶出栈括号 stack.pop() 与当前遍历括号 c 不对应,则提前返回 false
若在遍历字符串过程中,遇到了栈为空的情况,也提前返回false
若遍历完整个字符串,栈不为空,则返回false,若栈为空,则返回true
3.代码展示
class Solution {
public boolean isValid(String s) {
//左括号入栈,右括号判断
Stack<Character> stack = new Stack<>();
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == '(' || s.charAt(i) == '[' || s.charAt(i) == '{'){
stack.push(s.charAt(i));
}
if(stack.isEmpty()){
return false;
}
if(s.charAt(i) == ')' && stack.pop() != '('){
return false;
}
if(s.charAt(i) == ']' && stack.pop() != '['){
return false;
}
if(s.charAt(i) == '}' && stack.pop() != '{'){
return false;
}
}
return stack.isEmpty();
}
}
逆波兰表达式
1.题目要求
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。- 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"] 输出:6 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"] 输出:22 解释:该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 17 + 5 = 22
提示:
1 <= tokens.length <= 104
tokens[i]
是一个算符("+"
、"-"
、"*"
或"/"
),或是在范围[-200, 200]
内的一个整数
2.解题思路
数字全部入栈,遇到运算符弹出两个数字,运算结果再次入栈,最后返回栈顶元素即可
3.代码展示
class Solution {
public int evalRPN(String[] tokens) {
//数字全部入栈,遇到运算符弹出两个数字,运算结果再次入栈,
//最后返回栈顶元素即可
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < tokens.length; i++){
if(isNum(tokens[i])){
stack.push(Integer.parseInt(tokens[i]));
}else{
int fir = stack.pop();
int sec = stack.pop();
if(tokens[i].equals("+")){
stack.push(fir + sec);
}else if(tokens[i].equals("-")){
stack.push(sec-fir);
}else if(tokens[i].equals("*")){
stack.push(sec*fir);
}else{
if(fir == 0){
stack.push(0);
}else{
stack.push(sec/fir);
}
}
}
}
return stack.pop();
}
public static boolean isNum(String token){
return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
}
}