题目
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
- push(x) -- 将元素 x 推入栈中。
- pop() -- 删除栈顶的元素。
- top() -- 获取栈顶元素。
- getMin() -- 检索栈中的最小元素。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
1. 双栈
思路
我们使用两个栈:
- 一个栈存放全部的元素,push,pop都是正常操作这个正常栈。
- 另一个存放最小栈。 每次push,如果比最小栈的栈顶还小,我们就push进最小栈,否则不操作
- 每次pop的时候,我们都判断其是否和最小栈栈顶元素相同,如果相同,那么我们pop掉最小栈的栈顶元素即可
关键点
- 往minstack中 push的判断条件。 应该是stack为空或者x小于等于minstack栈顶元素
复杂度分析
- 时间复杂度:O(1)
- 空间复杂度:O(N)
Python
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.num_stk = []
self.min_stk = []
def push(self, x: int) -> None:
if(len(self.num_stk) == 0 or x <= self.min_stk[-1]):
self.min_stk.append(x)
self.num_stk.append(x)
def pop(self) -> None:
last = self.num_stk.pop(-1)
if(last == self.min_stk[-1]):
self.min_stk.pop(-1)
def top(self) -> int:
return self.num_stk[-1]
def getMin(self) -> int:
return self.min_stk[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
C++
class MinStack {
list<int> stk;
list<int> min;
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
if(min.empty() || min.front() >= x)
min.push_front(x);
stk.push_front(x);
}
void pop() {
if(stk.front() == min.front())
min.pop_front();
stk.pop_front();
}
int top() {
return stk.front();
}
int getMin() {
return min.front();
}
};
/**
* 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();
*/
2. 单栈
差值法
思路
符合直觉的方法是,每次对栈进行修改操作(push和pop)的时候更新最小值。 然后getMin只需要返回我们计算的最小值即可, top也是直接返回栈顶元素即可。 这种做法每次修改栈都需要更新最小值,因此时间复杂度是O(n).
是否有更高效的算法呢?答案是有的。
我们每次入栈的时候,保存的不再是真正的数字,而是它与当前最小值的差(当前元素没有入栈的时候的最小值)。 这样我们pop和top的时候拿到栈顶元素再加上上一个最小值即可。 另外我们在push和pop的时候去更新min,这样getMin的时候就简单了,直接返回min。
注意上面加粗的“上一个”,不是“当前的最小值”
经过上面的分析,问题的关键转化为“如何求得上一个最小值”,解决这个的关键点在于利用min。
pop或者top的时候:
- 如果栈顶元素小于0,说明栈顶是当前最小的元素,它出栈会对min造成影响,我们需要去更新min。 上一个最小的是“min - 栈顶元素”,我们需要将上一个最小值更新为当前的最小值
因为栈顶元素入栈的时候的通过
栈顶元素 = 真实值 - 上一个最小的元素
得到的, 而真实值 = min, 因此可以得出上一个最小的元素 = 真实值 -栈顶元素
- 如果栈顶元素大于0,说明它对最小值
没有影响
,上一个最小值就是上上个最小值。
关键点
- 最小栈存储的不应该是真实值,而是真实值和min的差值
- top的时候涉及到对数据的还原,这里千万注意是上一个最小值
复杂度分析
- 时间复杂度:O(1)
- 空间复杂度:O(1)
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.minV = float('inf')
self.stack = []
def push(self, x: int) -> None:
self.stack.append(x - self.minV)
if x < self.minV:
self.minV = x
def pop(self) -> None:
if not self.stack:
return
tmp = self.stack.pop()
if tmp < 0:
self.minV -= tmp
def top(self) -> int:
if not self.stack:
return
tmp = self.stack[-1]
if tmp < 0:
return self.minV
else:
return self.minV + tmp
def getMin(self) -> int:
return self.minV
C++