【LeetCode 手撕算法】(栈)有效括号、最小栈、字符串解码、每日温度、柱状图最大矩形

|-------------|--------------|-----------------|
| 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 numStack=new ArrayDeque<>();//披萨盒子用<> Deque 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 ![](https://i-blog.csdnimg.cn/direct/341a4f9317024568b4377bcd35352d12.png) **思路:**新建一个nums存每个位置的天数差,新建栈存天数;栈为空 入栈第一个;昨天出栈和今天比较,今天的温度大于昨天,则计算天数差,存入nums; 栈不为空,出栈操作持续,因为栈内都是未计算天数差的空值。 **注意:**出栈操作条件要判空 ![](https://i-blog.csdnimg.cn/direct/25ec79814fef46ecb75ed2db535e3aa6.png) ```java class Solution { public int[] dailyTemperatures(int[] temperatures) { //温度低入栈 //温度高出栈 计算天数差 int [] nums=new int[temperatures.length]; Deque stack=new ArrayDeque<>(); for(int i=0;itemperatures[stack.peek()]){ int num=stack.pop(); //昨天 nums[num]= i-num; //计算天数差,i比较大,存入tem的结果里 } stack.push(i);//比昨天温度低就入栈,对应nums表为空 } return nums; } } ``` *** ** * ** *** ## 84-柱状图最大矩形 > ![](https://i-blog.csdnimg.cn/direct/2f49d722f32145f994e548fcbf52cf36.png) > > ![](https://i-blog.csdnimg.cn/direct/85d10470ce3942f28cbe75f509374c13.png) > > ![](https://i-blog.csdnimg.cn/direct/426e228f3469443290a98d785404eb78.png) ![](https://i-blog.csdnimg.cn/direct/bacc37ac30a64d0e84840306825cd261.png) **思路:** 求柱状图矩形面积,一般优先选最高的柱子来求; 遍历所有,目前值为 i 的高; 前一个\>目前值 ,出栈, 更新h为前一个的,左右边界为两侧; 前一个\<目前值,入栈;(特殊情况 :若一直高上坡,右边界的h设为0;若一直低下坡,则 左边界设为界外-1) **注意:**考虑特殊情况1,当前值要判断是范围内还是最后一个; 考虑特殊情况2,一直出栈到边界,ok那设置左边界为-1; ```java class Solution { public int largestRectangleArea(int[] heights) { Deque 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()&&curHeimaxarea){maxarea=area;}//取最大面积 } stack.push(i); } return maxarea; } } ```

相关推荐
君义_noip44 分钟前
CSP-S 2025 提高级 第一轮(初赛) 阅读程序(3)
c++·算法·信息学奥赛·csp-s 初赛
happyprince1 小时前
05-FlagEmbedding 评估模块详解
算法
wuweijianlove1 小时前
算法优化的多目标平衡与性能建模研究的技术7
算法
_深海凉_1 小时前
LeetCode热题100-两两交换链表中的节点
算法·leetcode·链表
啊罗罗1 小时前
windows下,c++的axv2+fma/avx-vnni加速计算demo
c++·windows·算法
qq_283720051 小时前
Embedding 调优实战技巧:从原理到落地,打造高精度向量检索
python·算法·词嵌入·调优
czlczl200209251 小时前
MySQL 基于 GTID 的 Binlog 主从同步机制
java·jvm·mysql
Xpower 171 小时前
OpenClaw近一月版本更替讲解
人工智能·学习·算法
Ulyanov1 小时前
《从质点到位姿:基于Python与PyVista的导弹制导控制全栈仿真》: 刚体觉醒——6-DOF刚体动力学、四元数与全姿态解算
开发语言·人工智能·python·算法·系统仿真·雷达电子对抗仿真