Idiot-maker

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

https://leetcode.com/problems/min-stack/

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • getMin() -- Retrieve the minimum element in the stack.

解题思路:

要求实现一个stack,和一般的stack唯一不同的是,要求能返回当前栈内的最小值。而且,关键是要求这个时间必须是O(1)的。

唉,暂时想不出,写一个O(n)的吧。居然也AC了。

class MinStack {
    Stack<Integer> stack = new Stack<Integer>();
    int min = Integer.MAX_VALUE;
    
    public void push(int x) {
        stack.push(x);
        if(x < min) {
            min = x;
        }
    }

    public void pop() {
        int temp = stack.pop();
        if(temp == min) {
            min = Integer.MAX_VALUE;
            for(Integer i : stack) {
                if(i < min) {
                    min = i;
                }
            }
        }
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return min;
    }
}

但是这个解法肯定是不行的,要在O(1)时间内得到min,如果当前弹出的正是min,如何知道现在栈内剩余的最小值?

还是借鉴了大神的思路。因为本题要处理的数据结构是栈,栈的重要特点是FILO,先进后出。考虑当前最小值为min,那么在min后面进栈的大于min的值,都是会比min先出栈的。所以它们出栈对于当前栈的最小值根本没有影响,只要它们下面还有小于他们的数字。

借助上面的思想,我们要维护的其实是,这个min出栈后,它下面元素的最小值。

我们这里用一个minStack来保存这个“目前为止出现过的最小值”。如果目前进栈的数字比之前的最小数字还要小,或者等于(这里注意,一定要有等于),就将其塞进minStack。stack.pop()时,如果pop的数字等于minStack顶部,就将minStack也pop。

这样,每次弹出一个最小值,我们都能迅速知道剩下元素的最小值。弹出>min的值,minStack不动,因为对最小值根本没影响。塞进一个>min的值,minStack也不动,因为对“目前为止出现过的最小值”也没影响。塞进一个<=min的值,就将其也塞进minStack。因为“目前为止出现过的最小值”改变了。

代码如下:

class MinStack {
    Stack<Integer> stack = new Stack<Integer>();
    Stack<Integer> minStack = new Stack<Integer>();
    int min = Integer.MAX_VALUE;
    
    public void push(int x) {
        stack.push(x);
        // 这里<=是必须的,因为可能有两个min,否则minStack弹出一个,最小值就失去了
        if(minStack.empty() || x <= minStack.peek()) {
            minStack.push(x);
        }
    }

    public void pop() {
        int temp = stack.pop();
        if(temp == minStack.peek()) {
            minStack.pop();
        }
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return minStack.peek();
    }
}

总结一下,一般而言,我们取得一个集合中的最小值,是要O(n)的时间。但是本题利用stack的特点,先进来的后出去。也就是说,如果大的数字比小的数字后进来,他的进出压根不会对当前min产生任何影响。这个性质,使得我们只要关注边界,就是push和pop最小值的操作就可以了。

这是一道非常好的题目,不复杂,但是很看思路,和对数据结构的理解。

//20180930

Integer判断相等要用equals,不能直接用==。所以开始orderStack一直无法pop,泪流满面。

class MinStack {
    Stack<Integer> stack;
    Stack<Integer> orderStack;

    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<Integer>();
        orderStack = new Stack<Integer>();
    }
    
    public void push(int x) {
        stack.push(x);
        if (orderStack.empty() || x <= orderStack.peek()) {
            orderStack.push(x);
        }
    }
    
    public void pop() {
        if (stack.empty()) {
            return;
        }
        if (!orderStack.empty() && orderStack.peek().equals(stack.peek())) {
            orderStack.pop();
        }
        stack.pop();
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return orderStack.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

 

posted on 2015-04-15 15:46  NickyYe  阅读(207)  评论(0编辑  收藏  举报