|-------------|--------------|-----------------|
| push | 压栈,将元素放入栈顶 | push(e) |
| pop | 弹栈,移除并返回栈顶元素 | pop() |
| peek | 查看栈顶元素(不移除) | peek() |
| isEmpty | 判断栈是否为空 | isEmpty() |
| size | 获取栈中元素个数 | size() |
| 坑点 | 说明 | 解决方案 |
|---|---|---|
| pop/peek 前未判空 | 空栈调用会抛 EmptyStackException |
用前检查 !stack.isEmpty() |
用 == 比较 Integer |
比较两个 Integer 对象用 == 会出问题 |
用 .equals() |
| 忘记更新栈状态 | 只判断未弹出,导致死循环 | 确保 pop() 正确调用 |
| 单调栈边界 | 栈空时的 peek/pop 操作 | 用 isEmpty() 判断 |
| Deque 的 push/pop 与 addFirst/removeFirst | 两套方法等价,但混用可能混淆 | 统一用 push/pop/peek 语义 |
| 场景 | 核心思想 | 经典题目 |
|---|---|---|
| 括号匹配 | 遇到左括号压栈,遇到右括号弹出匹配 | LeetCode 20 |
| 表达式求值 | 操作数栈 + 运算符栈,处理优先级 | LeetCode 150 |
| 单调栈 | 维护单调递增/递减栈,找下一个更大/更小元素 | LeetCode 739, 42, 84 |
| DFS(深度优先搜索) | 用栈模拟递归,避免递归栈溢出 | LeetCode 94 |
| 撤销操作(Undo) | 每步操作压栈,撤销时弹出 | 系统设计题 |
| 浏览器前进后退 | 两个栈配合,前进栈 + 后退栈 | 系统设计题 |
自动装箱:
java
// 自动装箱:int → Integer
Integer a = 100; // 等价于 Integer.valueOf(100)
// 自动拆箱:Integer → int
int b = a; // 等价于 a.intValue()
// 在集合中自动装箱
Deque<Integer> stack = new ArrayDeque<>();
stack.push(512); // int 512 自动装箱成 Integer
int val = stack.pop(); // Integer 自动拆箱成 int
基本语句:
java
import java.util.*;
public class StackDemo {
public static void main(String[] args) {
// 1. 创建栈
Deque<Character> stack = new ArrayDeque<>();
// 2. 压栈 push
stack.push('a');
stack.push('b');
stack.push('c');
System.out.println(stack); // [a, b, c](栈顶在右)
// 3. 查看栈顶 peek
char top = stack.peek();
System.out.println(top); // c(不出栈)
// 4. 弹栈 pop
char popped = stack.pop();
System.out.println(popped); // c
System.out.println(stack); // [a, b]
// 5. 判空 isEmpty
boolean empty = stack.isEmpty();
System.out.println(empty); // false
// 6. 获取大小 size
int size = stack.size();
System.out.println(size); // 2
// 7. 清空栈(方法一:逐个弹出)
while (!stack.isEmpty()) {
stack.pop();
}
// 8. 清空栈(方法二:clear)
// stack.clear();
System.out.println(stack.isEmpty()); // true
}
}
20-有效的括号
**思路:**遍历每个字符,先把左括号压入栈,到右括号时出栈进行对比。
**注意:遍历s用toCharArray()**来变成单字符数组;
判断右括号,要考虑特殊情况 即栈空;
整体返回 不直接返true ,万一奇数个括号,因此返回**stack.isEmpty.()**是否为空
java
class Solution {
public boolean isValid(String s) {
Deque <Character> stack=new ArrayDeque<>();
//左括号压入栈,右括号匹配就出栈
for(char c:s.toCharArray()){ //将s换成字符数组
if(c=='('||c=='['||c=='{'){//判断左括号,入栈
stack.push(c);
}else{//判断右括号
if(stack.isEmpty()){ //栈为空,即无对应左括号
return false;
}
char pop= stack.pop();//出栈判断是否左右匹配
if(!isMatch(pop,c)){
return false;
}
}
}
return stack.isEmpty();//栈为空,即偶数,则全部匹配成功
}
public boolean isMatch(char pop,char c){
if(pop=='('&&c==')'||pop=='['&&c==']'||pop=='{'&&c=='}'){
return true;
}else{return false;}
}
}
155-最小栈
**思路:按要求来,新建minstack来存历史最小值,最顶部就是当前最小值,只要更小就入minstack,所以其是越来越小。获取最小值直接minstack.peek()**就行
注意:int是披萨(值) ,Integer是披萨盒(地址),两者比较用.equals() 比较值,用**=**是判断两个地址是否相等,Deque等不接受int,只接受Integer盒子;
stack.pop()在if条件里就算执行了一次pop,不需要再写pop操作了;
如果没有最小值这个概念要求,直接 stack.pop(),就行了
java
class MinStack {
Deque <Integer>stack;
Deque <Integer>minstack;
public MinStack() {
stack=new ArrayDeque<>();
minstack=new ArrayDeque<>();
}
public void push(int val) {
stack.push(val);
if(minstack.isEmpty()||val<=minstack.peek()){//minstack为空 或 <当前最小值
minstack.push(val);
}
}
public void pop() {
if(stack.pop().equals(minstack.peek())){ //pop的与minstack顶部(当前最小值)相等时
minstack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return minstack.peek();
}
}
/**
* 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();
*/
394-字符串解码
思路:
遍历每个字符:
数字 → 累加 num
字母 → 拼到当前结果 curr
[ → 把 num 和 curr 压栈,然后重置 num=0, curr=""
] → 弹出 num 和 栈顶字符串,把 curr 重复 num 遍,再拼到栈顶字符串后面
**注意:**StringBuilder是可变字符串;
注意StringBuilder、String和char的格式,必须统一;
String是定长,StringBuilder是可变长;
num入栈出栈之后要置0;
需要使用temp来接住从栈里弹出来的字符串,方便重复操作,重复完变成当前值cur ;
java
class Solution {
public String decodeString(String s) {
Deque <Integer> numStack=new ArrayDeque<>();//披萨盒子用<>
Deque <String> curStack=new ArrayDeque<>();//披萨盒子用<>
int num=0;
StringBuilder cur=new StringBuilder(); //当前串,披萨不用<>
for(char c:s.toCharArray()){//String要变成Char型
if(c>='0'&&c<='9'){
num=num*10+c-'0';
}else if(c=='['){
numStack.push(num);
curStack.push(cur.toString()); //Char要变成String型
num=0;
cur=new StringBuilder();
}else if(c>='a'&&c<='z'){
cur.append(c); //字母就拼接在cur上
}else if(c==']'){
num=numStack.pop();
StringBuilder temp=new StringBuilder(curStack.pop());
for(int i=0;i<num;i++){temp.append(cur);}//cur开始重复
cur = temp;
num=0;
}
}
return cur.toString();
}
}
739-每日温度
**思路:**新建一个nums存每个位置的天数差,新建栈存天数;栈为空 入栈第一个;昨天出栈和今天比较,今天的温度大于昨天,则计算天数差,存入nums; 栈不为空,出栈操作持续,因为栈内都是未计算天数差的空值。
**注意:**出栈操作条件要判空

java
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
//温度低入栈
//温度高出栈 计算天数差
int [] nums=new int[temperatures.length];
Deque<Integer> stack=new ArrayDeque<>();
for(int i=0;i<temperatures.length;i++){
//栈不为空 且 比昨天温度高,就出栈
while(!stack.isEmpty()&&temperatures[i]>temperatures[stack.peek()]){
int num=stack.pop(); //昨天
nums[num]= i-num; //计算天数差,i比较大,存入tem的结果里
}
stack.push(i);//比昨天温度低就入栈,对应nums表为空
}
return nums;
}
}
84-柱状图最大矩形

思路: 求柱状图矩形面积,一般优先选最高的柱子来求;
遍历所有,目前值为 i 的高;
前一个>目前值 ,出栈, 更新h为前一个的,左右边界为两侧;
前一个<目前值,入栈;(特殊情况 :若一直高上坡,右边界的h设为0;若一直低下坡,则 左边界设为界外-1)
**注意:**考虑特殊情况1,当前值要判断是范围内还是最后一个;
考虑特殊情况2,一直出栈到边界,ok那设置左边界为-1;
java
class Solution {
public int largestRectangleArea(int[] heights) {
Deque<Integer> stack=new ArrayDeque<>();
int maxarea=0;
int area=0;
//出栈判断与之前栈顶大小,小则左边界向左走,大则入栈,一直大下去结尾放个0的哨兵
for(int i=0;i<=heights.length;i++){
int curHei=(i==heights.length)?0:heights[i];//当前高度,多设置哨兵0在最后,以防一直上坡
while(!stack.isEmpty()&&curHei<heights[stack.peek()]){
int h=heights[stack.pop()];//上一个实际高度,取出栈顶索引
//当栈空,即左边都比当前大,边界设为-1;左边界为出站后,新栈的索引
int left=stack.isEmpty()?-1:stack.peek();
int right=i;//右边界是当前值
area=(right-left-1)*h;
if(area>maxarea){maxarea=area;}//取最大面积
}
stack.push(i);
}
return maxarea;
}
}









