题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。


  首先读懂题目,需要保留所有栈的特性(先进后出),并且该栈中有能够提供找到最小元素的min函数。普通的栈是无法实现的。说白了就是让你设计一个栈,其中有一个函数时可以返回最小值的。显然这个栈不是让你写从零写起,你可以依托于包中的栈的普通方法,而把焦点在如何实现min函数
  不能用一个变量记录最小值,因为当最小值弹栈后,该变量就得变成新的最小值,这个不容易实现。所以需要定义一个辅助的数据结构,可以记录多个变量,可以随着原来的栈的弹出压入而更新对应的最小值。
  第一想法是使用最小堆,但是最小堆还需要实现。既然本身可以依托于包中的栈,那么比较讨巧的做法就是用一个辅助栈。
  因此需要设计辅助栈的压入规则和弹出规则:


写法1:

  用一个栈data保存数据,用另外一个栈min保存依次入栈最小的数
比如,data中依次入栈,5, 4, 3, 8, 10, 11, 12, 1
   则min依次入栈,5, 4, 3,3, 3, 3, 3, 1
每次入栈的时候,如果入栈的元素比min中的栈顶元素小或等于则两边都入栈,否则辅助栈压入一个当前的最小值。这样可以保证两个栈的入栈的数量是一致的。

import java.util.Stack;

public class Solution {
    Stack<Integer> stack_data=new Stack<Integer>();//原来的栈
    Stack<Integer> stack_min=new Stack<Integer>();//辅助栈

    public void push(int node) {
        stack_data.push(node);//原来的栈肯定要入的
        if(stack_min.empty() || stack_min.peek()>node) {//为空就使用不了peek
            stack_min.push(node);//当前数更小则当前数入栈
        }else {
            stack_min.push(stack_min.peek());//否则压入辅助栈的最小值
        }       
    }

    public void pop() {
        if(!stack_data.empty()) {//同时弹
            stack_data.pop();
            stack_min.pop();
        }
    }  
    public int top() {//返回原栈的栈顶元素
        return stack_data.peek();
    } 
    public int min() {//返回辅助栈的栈顶元素
        return stack_min.peek();
    }
}

写法2

  用一个栈data保存数据,用另外一个栈min保存依次入栈最小的数
比如,data中依次入栈,5, 4, 3, 8, 10, 11, 12, 1
   则min依次入栈,5, 4, 3,null, null, null, null, 1
null就是不入栈。也就是只有出现最小值时,辅助栈才会入栈。而弹出时,原栈和辅助栈的栈顶相同时,辅助栈才会弹栈。

import java.util.Stack;

public class Solution {
    Stack<Integer> stack_data=new Stack<Integer>();
    Stack<Integer> stack_min=new Stack<Integer>();

    public void push(int node) {
        stack_data.push(node);//反正原栈肯定要入的
        if(stack_min.empty() || stack_min.peek()>node) {
            //出现较小值才入栈,否则不操作
            stack_min.push(node);
        }      
    }    
    public void pop() {
        if(!stack_data.empty()) {//首先判断不为空
            if(stack_data.peek() != stack_min.peek())
            //不相等,说明弹出的不是当前最小值,原栈弹出就可以
                stack_data.pop();
            else{//是最小值,两个栈一起弹
                stack_data.pop();
                stack_min.pop();
            }            
        }
    }     
    public int top() {
        return stack_data.peek();
    }  
    public int min() {
        return stack_min.peek();
    }
}

总结:其实很多算法题考点不同,本题的考点在于如何实现Min函数,因此不需要考虑太多栈的设计考察一个栈如何设计,并不是说栈的设计不重要,只是本题的侧重点不在与栈的设计,有些大佬功底比较厚,考虑的也比较多,这也正常。非大佬就把握好考点就好啦。
附上左神的一张图,构造函数都搞出来了,把一些思想用进来就很强势。还有些大佬在回答中进行扩容的,是真的强。
说明:这个和写法2的原理相同
图片说明