zoukankan      html  css  js  c++  java
  • 设计一个有getMin功能的栈

    命题

    实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作

    要求:

    1. pop、push、getMin操作的时间复杂度都是O(1);
    2. 设计的栈类型可以使用现成的栈结构。

    难度 ♥(压力好大...)

    设计思路:

    两个栈-普通栈+getMin栈,它的主要目的还是要获取到stack对象的最小值,如果两个栈同为最小值也一并被pop()方法弹出(实现弹栈的基本功能罢了)

    方案一

    让较大的数不压入最小值的栈中,stackMin不做任何操作继续保持原样,这样即可通过栈对象的peek()方法返回最小值

    这里写图片描述

    具体实现

    package com.demo.mystack;
    
    import java.util.Stack;
    /**
     * 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作
     * 要求:
     * 1、pop、push、getMin操作的时间复杂度都是O(1)
     * 2、设计的栈类型可以使用现成的栈结构
     */
    
    /**
     * @author lorem
     * @date 2018/8/19
     */
    public class MyStack {
        /**
         * stackData 基本信息栈
         * stackMin 最小栈
         **/
        private Stack<Integer> stackData;
        private Stack<Integer> stackMin;
        
        @Test
        public void test(){
           MyStack myStack = new MyStack();
            myStack.push(2);
            myStack.push(5);
            myStack.push(4);
            myStack.push(1);
            System.out.println(myStack.pop());
            System.out.println(myStack.getmin());
            MyStack myStack1 = new MyStack();
            myStack1.pop();
        }
    /**
    * 通过构造方法,实例化两个Stack对象 stackData、stackMin
    */
        public MyStack(){
            this.stackData = new Stack<Integer>();
            this.stackMin = new Stack<Integer>();
        }
        
        /**
         * push方法将元素压栈
         */
        private void push(int newNum){
            if (this.stackMin.isEmpty()){
                this.stackMin.push(newNum);
            }else if(newNum <= this.getmin()){
                this.stackMin.push(newNum);
            }
            this.stackData.push(newNum);
        }
    
        /**
         * stackData.pop()返回值赋值给value
         * value比对最小值,如果相等则将最小栈中的元素也弹出
         * @return 返回value
         */
        private int pop(){
        //因为最大值会先入stackData栈中所以只要判断此是否为空即可
            if (this.stackData.isEmpty()){
                throw  new RuntimeException("your stack is empty");
            }
            int value = this.stackData.pop();
            // 这样的判断也是为了避免NPE
            if (value==this.getmin()){
                this.stackMin.pop();
            }
            return value;
        }
    
    
        /**
         *getmin 获取最小元素
         * 利用peek方法,返回的元素并不会删除
         *
         * @return 最小栈元素
         */
        private int getmin(){
            if (this.stackMin.isEmpty()){
                throw new RuntimeException("your stack is emtry");
            }
            return this.stackMin.peek();
        }
    }
    
    

    方案二

    在遇到较大的值时,压入上一次重复的较小值

    这里写图片描述

    具体实现

    package com.demo.mystack;
    
    import org.junit.Test;
    
    import java.util.Stack;
    
    /**
     * @author lorem
     * @date 2018/8/19
     */
    public class MyStack1 {
        /**
         *  stackData 基本信息栈
         *  stackMin 最小栈
         */
        private Stack<Integer> stackData;
        private Stack<Integer> stackMin;
    
        /**
         * 通过初始化构造函数创建两个相关对象
         */
        public MyStack1(){
           this.stackData = new Stack<Integer>();
           this.stackMin = new Stack<Integer>();
        }
    
        @Test
        public void test(){
            MyStack1 myStack1 = new MyStack1();
            myStack1.push(2);
            myStack1.push(5);
            myStack1.push(4);
            myStack1.push(1);
            System.out.println(myStack1.pop());
            System.out.println(myStack1.getmin());
        }
        /**
         *
         * @param newNum
         *
         */
        public void push(int newNum){
            if (this.stackMin.isEmpty()){
                this.stackMin.push(newNum);
            }else if (newNum < this.getmin()){
                this.stackMin.push(newNum);
            }else {
                int newMin = this.stackMin.peek();
                this.stackMin.push(newMin);
            }
            this.stackData.push(newNum);
        }
    
        public int pop(){
            if (this.stackData.isEmpty()){
                throw new RuntimeException("your stack is empty");
            }
            this.stackMin.pop();
            return this.stackData.pop();
        }
    
        public int getmin(){
            if (this.stackMin.isEmpty()){
                throw new RuntimeException("your stack is emtry");
            }
            return this.stackMin.peek();
        }
    }
    
    

    总结

    两种方案的最终目的都是让较大的数不压入最小值的栈中,方案一压栈时稍省空间,弹栈时稍费空间;方案二则压栈时费空间,弹栈时稍省空间。

    因为方案一的实现在遇到较大值时,不会压入任何数据保持原样,所以在弹栈时需要做一个额外的判断,以免出现NPE。

    int value = this.stackData.pop();
       // 这样的判断也是为了避免NPE
     if (value==this.getmin()){
    	   this.stackMin.pop();
    }
    

    而方案二stackData与stackMin两个栈空间容量是等同的,所以,在弹栈时则比较顺便了

    this.stackMin.pop();
    this.stackData.pop();
    

    也就是说,如果只是进行压栈操作而对弹栈操作较少的情况下用方案一;如果对弹栈操作较为频繁就用方案二。

    - The End -

    知识共享许可协议 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

  • 相关阅读:
    简单工厂模式&工厂方法模式&抽象工厂模式的区别及优缺点及使用场景
    JDK1.8的新特性
    在Button样式中添加EventSetter,理解路由事件
    关于C#低版本升级高版本时,项目中引用Microsoft.Office.Interop.Word,程序提示不存在类型或命名空间名office.
    无法安装或运行此应用程序。该应用程序要求首先在"全局程序集缓存(GAC)"中安装程序集
    C#winform跨窗体传值和调用事件的办法
    C#线程处理:七、线程实列
    C#线程处理:六、线程同步(三)
    C#线程处理:五、线程同步(二)
    C#线程处理:四、线程同步
  • 原文地址:https://www.cnblogs.com/hoochanlon/p/9676623.html
Copyright © 2011-2022 走看看