最小(大)栈--双栈/单栈两种解法

最小(大)栈

标明:以下代码为最小栈讲解,求最大栈只需将入栈判断条件做以修改即可。

题目描述:
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。

 push(x) -- 将元素 x 推入栈中。
 pop() -- 删除栈顶的元素。
 top() -- 获取栈顶元素。
 getMin() -- 检索栈中的最小元素。
测试示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.
题目解析:

我们通过解析题目可以知道,该题实际上是要求我们自定义一个栈,实现简单的入栈、出栈、弹出最顶层元素三个基础功能。最核心的是要实现返回最小栈元素(要求时间复杂度在常数范围内,即O(常数))。

两种解题思路:

针对于题目对时间复杂度的要求,我们可有以下两种解题思路:

1.双栈思路。因题目只对时间复杂度有要求,而对空间复杂度无要求。因此我们可以创建两个栈,一个栈用于存储实际数据,另一个栈用于存储最小元素,getMin()方法只需直接返回存储最小元素栈的最顶层元素即可。

双栈思路时间复杂度为O(1),空间复杂度为O(n)。

2.单栈思路。假设该题对时间复杂度和空间复杂度都要求为O(1)时,我们就可使用该方法实现。单栈顾名思义就是只创建一个栈,我们进行入栈操作时可push()两次,第一次为实际数据,第二次为最小元素(即每个实际数据后面均跟着最小元素),getMin()方法只需直接返回栈顶元素即可。

双栈思路和单栈思路图解:
双栈思路:

在这里插入图片描述

单栈思路:

在这里插入图片描述

双栈思路实现代码:
import java.util.Stack;
class MinStack {
       //创建dataStack栈存放实际元素
        private Stack<Integer> dataStack;
       //创建minDataStack栈存放最小元素
        private Stack<Integer> minDataStack;
        /** initialize your data structure here. */
        public MinStack() {
            dataStack=new Stack<>();
            minDataStack=new Stack<>();
        }
        //入栈
        public void push(int x) {
            //当minDataStack栈为空或入栈数据小于或等于该栈栈顶元素时入栈
            //将<=改为>=即可dataStack栈中存储的为最大元素
            if(minDataStack.isEmpty()||x<=minDataStack.peek()){
                minDataStack.push(x);
            }
            //dataStack栈存放实际元素,无论如何都会入栈
            dataStack.push(x);
        }
        //出栈
        public void pop() {
            //如果存放实际元素栈要出栈元素与minDataStack栈顶元素相等,则minDataStack栈顶元素也需出队,若不相等则只需dataStack栈顶元素出队即可
            //为什么minDataStack栈顶元素若与dataStack元素出栈元素相等,minDataStack栈顶元素也要出栈呢?原因是minDataStack栈顶存放的是最小元素,若dataStack要出栈元素与最小元素相同则表明dataStack要出栈元素即为栈内最小元素,出栈后最小元素将更新,故minDataStack栈顶元素也要出栈,否则minStack已经更新了最小元素,而minDataStack内最小元素还为旧值
            //此处Stack创建为包装类Integer,包装类比较内容相等时需用equals方法,==比较的是指向堆内存的地址是否相等
            if(dataStack.peek().equals(minDataStack.peek())){
                minDataStack.pop();
            }
            //无论如何调用一次pop()方法存放实际元素的栈需要出栈栈顶元素
            dataStack.pop();
        }
        public int top() {
            //返回存放数据的栈的栈顶元素
            return dataStack.peek();
        }
        public int getMin() {
            //返回存放最小元素栈的栈顶元素即可
            return minDataStack.peek();
        }
    }
public class Main{
    public static void main(String[] args) {
        MinStack stackTest=new MinStack();
        stackTest.push(1);
        stackTest.push(2);
        stackTest.push(3);
        System.out.println(stackTest.top());
        stackTest.pop();
        System.out.println(stackTest.getMin());
    }
}
/**
3
1
**/
单栈思路:
import java.util.Stack;

//最小(大)栈
//单栈--->push两次,实际数据后面跟最小元素
class MinStack{
    private Stack<Integer> stack;
    public MinStack() {
        stack=new Stack<>();
    }

    public void push(int x){
        //当栈为空时,第一个入栈的元素也为最小元素
        if(stack.isEmpty()){
            stack.push(x);
            stack.push(x);
        }else {//当栈内存在元素时
            int temp=stack.peek();//将当前最小元素暂存
            stack.push(x);//将实际元素入栈
            //将新入栈元素与当前最小元素比较
            if(x<=temp){//若小于等于更新最小值将<=改为>=即可dataStack栈中存储的为最大元素
                stack.push(x);
            }else {//若大于则依旧将最小值入栈
                stack.push(temp);
            }
        }
    }
    public void pop(){
        if(stack.isEmpty()){
            System.out.println("当前栈为空");
            return;
        }
        //删除两次即可
        stack.pop();
        stack.pop();
    }
    //弹出栈顶元素
    //我们知道栈顶元素为最小值,不一定是实际最后一个入栈的元素,故弹出栈顶元素我们需要先将最小元素出栈保存,然后返回实际栈顶元素,最后再将最小元素入栈
    public int top(){
        if(stack.isEmpty()){
            System.out.println("当前栈为空");
        }
        int result=stack.pop();
        int data=stack.peek();
        stack.push(result);
        return data;
    }
    //最小值为栈顶元素
    public int getMin(){
        return stack.peek();
    }
}
public class Main{
    public static void main(String[] args) {
        MinStack stackTest=new MinStack();
        stackTest.push(1);
        stackTest.push(2);
        stackTest.push(3);
        System.out.println(stackTest.top());
        stackTest.pop();
        System.out.println(stackTest.getMin());
    }
}
/**
3
1
**/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值