剑指offer-包含min函数的栈
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路一:利用一个变量min,每次push时,比较push的值和min的值,若push值小于min的值则将min值进行更新。
思路一分析:该方法可以获得当前栈的最小值,但若最小值被pop出去后,想重新获得最小值则需要重新遍历栈内元素,再更新最小值了。所以这个方法的时间复杂度为O(n),空间复杂度为O(1)。
思路二:申请一个辅助栈mins,mins中保存最小值,当push的值小于mins的栈顶元素时,将push值同时压入mins和元数据栈。当push值大于mins的栈顶元素时,将push值压入元数据栈,将mins栈顶元素再次压入mins栈。
思路二分析,该方法的时间复杂度降到了O(1),但是空间复杂度为O(n)。
算法优化:
由此可以看出辅助栈中有大量重复的值,这点可以进行优化。可以在push时判断一下,如果比最小值还大,那么就不加入辅助栈。pop时如果要pop的数据不等于辅助栈栈顶元素,则辅助栈的栈顶就不出栈。如下图所示:
上述方法的问题在于如果要push一个和最小值相同的数进栈则辅助栈和元数据栈中都要push。否则最小值出栈后下一个最小值就不对了。如下图所示
针对上述问题的优化思路:在mins栈中保存最小值的索引。如下图所示
最终代码:
import java.util.ArrayList; import java.util.List; /** * @author xiaoshi on 2018/9/1. */ public class MinStack { private List<Integer> data = new ArrayList<Integer>(); private List<Integer> mins = new ArrayList<Integer>(); public void push(int num) throws Exception { data.add(num); if(mins.size() == 0) { // 初始化mins mins.add(0); } else { // 辅助栈mins push最小值的索引 int min = getMin(); if (num < min) { mins.add(data.size() - 1); } } } public int pop() throws Exception { // 栈空,抛出异常 if(data.size() == 0) { throw new Exception("栈为空"); } // pop时先获取索引 int popIndex = data.size() - 1; // 获取mins栈顶元素,它是最小值索引 int minIndex = mins.get(mins.size() - 1); // 如果pop出去的索引就是最小值索引,mins才出栈 if(popIndex == minIndex) { mins.remove(mins.size() - 1); } return data.remove(data.size() - 1); } public int getMin() throws Exception { // 栈空,抛出异常 if(data.size() == 0) { throw new Exception("栈为空"); } // 获取mins栈顶元素,它是最小值索引 int minIndex = mins.get(mins.size() - 1); return data.get(minIndex); } }