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(); */