java数据结构与算法刷题-----LeetCode155. 最小栈

本文介绍了两种方法来解决Java中的数据结构问题,即使用辅助最小栈和差值法,以实现实时获取栈中最小值,同时保持时间复杂度为O(1),空间复杂度分别为O(n)和O(1)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.youkuaiyun.com/grd_java/article/details/123063846

在这里插入图片描述

1. 法一:使用辅助最小栈

解题思路:时间复杂度O(1),空间复杂度O(n)
  1. 我们出栈和入栈时,要同步维护一个最小值栈
  2. 最小值栈主要保存当前最小值
  3. 这样,我们就可以实时获取当前栈中最小值
  4. 图解如下:
  1. 入栈-2,则栈顶元素为-2,当前最小值也是-2
    在这里插入图片描述
  2. 入栈0,此时栈顶为0,但是最小值还是-2,所以最小栈依然入栈-2
    在这里插入图片描述
  3. 入栈-3,当前最小值为-2,但是-3比-2小,所以最小栈入栈-3
    在这里插入图片描述
  4. 此时执行getMin()操作获取当前最小值,那么直接获取最小栈的栈顶-3.
  5. 此时执行出栈操作,那么栈顶元素为-3. 同样的,最小栈也需要出栈
    在这里插入图片描述
  6. 此时执行top操作,也就是获取栈顶元素,那么直接获取栈顶的0即可
  7. 再次执行getMin()获取最小值,那么直接获取最小栈的栈顶-2即可。
代码

在这里插入图片描述

class MinStack {
    //用链表模拟栈,作为栈存储的容器
    class ListNode {
        int val;//当前结点的值
        int min;//当前最小值。用一个变量模拟最小值栈
        ListNode next;//下一个结点

        public ListNode() {

        }

        public ListNode(int val, int min, ListNode next) {
            this.val = val;
            this.min = min;//min就是最小值栈
            this.next = next;
        }
    }

    ListNode head;//头结点

    public MinStack() {
        head = new ListNode();//头结点初始化
    }
    //入栈操作
    public void push(int val) {
        ListNode next = head.next, cur;//获取栈顶元素next,cur是当前要插入结点
        if (next != null && next.min < val) {//如果栈不为空
            //但是当前栈中最小值,比val更小,那么将当前结点入栈,但是最小值依然保存next.min
            cur = new ListNode(val, next.min, next);
        }
        else {//如果栈为空,直接入栈当前结点
            //或者栈不为空,但是当前结点的值更小的话,那么新的最小值为当前的val值
            cur = new ListNode(val, val, next);
        }
        head.next = cur;//头插法,实现先入后出
    }
    //出栈
    public void pop() {
        ListNode del = head.next;//取出栈顶元素
        head.next = del.next;//头结点指向新的栈顶元素
    }
    //获取栈顶元素的值
    public int top() {
        return head.next.val;
    }
    //获取最小值,就在栈顶元素的min变量中保存
    public int getMin() {
        return head.next.min;
    }
}

/**
 * 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();
 */

/**
 * 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. 法二:使用差值

解题思路:时间复杂度O(1), 空间复杂度O(1)
  1. 用变量min保存当前栈中最小值,而入栈时,保存当前值与最小值的差值
  1. 初次入栈,最小值和入栈值相同,所以差值为0
    在这里插入图片描述
  2. 第二次入栈时,入栈0,与-2差值为0 - ( -2 ) = 2
    在这里插入图片描述
  3. 第3次入栈时,入-3,与-2的差值为 ( -3 ) - ( -2 ) = -1. 最小值更新为-3.我们发现如果遇到更小值,那么差值为负数,并且更新了最小值
    在这里插入图片描述
  4. 此时执行getMin()获取最小值,直接返回Min变量保存的-3即可
  5. 此时执行出栈操作,我们发现,栈顶元素为负数,说明他就是当前最小值,那么需要执行逆运算获取接下来的最小值。
  1. 获取时的式子是:当前值 - 最小值 = 入栈值,(-3) - (-2) = 1并令当前值-3成为新的最小值
  2. 则当前 , 需要出栈的元素值,就是当前最小值-3
  3. 而新的最小值需要逆运算得出,最小值 = 当前值(就是当前最小值-3) - 入栈值 = (-3) - (-1) = -2. 故,出栈后,新的最小值为-2
    在这里插入图片描述
  1. 此时执行top操作获取栈顶元素,也需要逆操作。
  1. 如果栈顶元素<=0说明,当前最小值就是栈顶元素
  2. 如果不是,那就是通过式子:入栈值 = 原来的值 - 最小值得到的
  3. 还原则需要:原来的值 = 入栈值+最小值 = 2 + (-2) = 0. 故当前栈顶元素为0.
  1. 此时执行getMin()操作,获取最小值,依然获取MIn保存的值-2即可。
代码

在这里插入图片描述

class MinStack {
    // 记录每个元素与【未压入】该元素时栈中最小元素的差值
    LinkedList<Long> stack;
    // 当前【已压入】栈中元素的最小值
    private long min;
    public MinStack() {
        stack = new LinkedList();//初始化栈
    }
    
    public void push(int val) {
        // 压入第一个元素
        if(stack.isEmpty()){//栈为空时
            min = val;//最小值就是当前值
            stack.addFirst(0L);//头插法,当前值和最小值相同,所以他俩的差值为0
            return;
        }
        // 栈不为空时,每次压入计算与min的差值后压入结果
        stack.push((long)val-min);
        // 更新min,保存更小的
        min = Math.min((long)val,min);
        // 上面两个语句是不能颠倒的!一定是先压入,在更新,因为min一定是当前栈中的最小值
    }
    
    public void pop() {
        long pop = stack.removeFirst();
        // 当弹出元素小于0时,说明弹出元素是当前栈中的最小值,要更新最小值
        if(pop<0){
            // 因为对于当前弹出的元素而言,计算压入栈中的值时,计算的是该元素与【未压入】该元素时
            // 栈中元素的最小值的差值,故弹出该元素后栈中的最小值就是未压入该元素时的最小值
            // 即当前元素的值(min)减去两者的差值
            long lastMin = min;
            min = lastMin - pop;
        }
        // 若大于等于0,不会对min有影响
    }
    
    public int top() {
        long peek = stack.peek();
        // 若当前栈顶小于等于0,说明最小值就是栈顶元素
        if(peek<=0) return (int)min;
        // 否则就是min+peek
        return (int)(min+peek);
    }
    
    public int getMin() {
        return (int)min;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydenergy_殷志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值