剑指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);
    }

}

 

posted @ 2018-09-06 18:54  朝朝暮暮dx  阅读(129)  评论(0编辑  收藏  举报