【Leetcode 30天挑战活动】Day 10. Min Stack

害,昨天犯懒,一晚上没学习,就没做(爬
今天补上

题目描述

设计一个最小栈,可以完成栈最基本的push、pop、top功能,除此之外要实现一个getMin方法,在常数时间内得到当前栈中的最小值

解题思路

(1)一个不符合题目要求的做法:使用List结构来模拟栈的操作,push即加入list,pop和top则是操作list的最后一个元素,getMin则需要对list进行一个遍历操作找到最小值。由于需要遍历,getMin的时间复杂度为O(N),不符合题目要求。

(2) 想办法存下最小值。因为题目要求在常数时间内返回最小值,那么就意味着我们必须采用某种方法提前存下最小值,而不是等到要获得最小值时才去所有的数里面找。对于正常存入最小栈中的数据,我们可以就直接采用一个栈来保存,而对于保存最小值,有以下几种方法:
图片解说来自题解:https://leetcode-cn.com/problems/min-stack/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-38/

法一: 使用一个额外的栈保存最小值。
在最开始的时候我考虑过用一个额外的变量来保存最小值,而变量的问题在于:当前最小值被pop出去之后,第二小的元素(即pop之后的最小值)应该怎么获取?也就是说,在这道题目中,保存最小值并非只保存一个当前数据就可以,而是要保存一个 “最小值序列”
因此就会想到,是不是可以用一个额外的数据结构来保存这个最小值序列呢?
法一就是使用了一个额外的栈,具体做法是:当第一个元素入栈时,将其加入最小栈;后续元素入(基本)栈时,将其与最小栈的栈顶比较,如果比栈顶元素大,就不管,反之就将这个元素加入最小栈
在这里插入图片描述

代码如下:

class MinStack {

    /** initialize your data structure here. */
    
    Stack<Integer> stack;
    Stack<Integer> minStack;

    public MinStack() {
        this.stack = new Stack<>();
        this.minStack = new Stack<>();
    }
    
    public void push(int x) {
        stack.push(x);
        
        if (minStack.size() == 0 || x <= minStack.peek()) {
            minStack.push(x);
        }
    }
    
    public void pop() {
        int tmp = stack.peek();
        stack.pop();
        
        if (minStack.peek() == tmp) {
            minStack.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

法二: 只使用一个栈,同时保存数据序列和最小值。
主要问题就是,当最小值有更新的时候,如何把前一个最小值保存下来。只使用一个栈时可以进行如下操作:
(1)当最小值更新时,先将前一个最小值压栈,然后更新最小值且将当前最小值压栈
(2)当出栈的数值和当前最小值相等时,再进行一次出栈操作,也就是恢复前一个最小值
在这里插入图片描述
(按照这个思路写的代码也比较简单,就不再重复了)

(3) (2)中的方法都是基于直接使用Java的栈来保存数据序列,当然我们也可以不用自带的栈,可以考虑用一个链表,在每一个Node节点中都增加一个min字段,每次push的时候就确定该node的min值,直接从底层数据结构就解决了最小值的问题。
这里需要注意,由于我们每次都是操作栈顶元素,因此每次push的时候都可以将节点加入首部
以下代码来自题解,也比较简单:

class MinStack {
    class Node{
        int value;
        int min;
        Node next;

        Node(int x, int min){
            this.value=x;
            this.min=min;
            next = null;
        }
    }
    Node head;
    //每次加入的节点放到头部
    public void push(int x) {
        if(null==head){
            head = new Node(x,x);
        }else{
            //当前值和之前头结点的最小值较小的做为当前的 min
            Node n = new Node(x, Math.min(x,head.min));
            n.next=head;
            head=n;
        }
    }

    public void pop() {
        if(head!=null)
            head =head.next;
    }

    public int top() {
        if(head!=null)
            return head.value;
        return -1;
    }

    public int getMin() {
        if(null!=head)
            return head.min;
        return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值