leecode/problems/155.min-stack.md

305 lines
6.9 KiB
Markdown
Raw Normal View History

2020-05-22 18:17:19 +08:00
# 题目地址
https://leetcode.com/problems/min-stack/description/
# 题目描述
```
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.
Example:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> Returns -3.
minStack.pop();
minStack.top(); --> Returns 0.
minStack.getMin(); --> Returns -2.
```
# 差值法
## 思路
符合直觉的方法是每次对栈进行修改操作push和pop的时候更新最小值。 然后getMin只需要返回我们计算的最小值即可
top也是直接返回栈顶元素即可。 这种做法每次修改栈都需要更新最小值因此时间复杂度是O(n).
![](https://pic.leetcode-cn.com/7beed41b8dc0325445721a36b7db34e1af902441b67996d2eeadcb1f5a5e33d9.jpg)
是否有更高效的算法呢?答案是有的。
我们每次入栈的时候,保存的不再是真正的数字,而是它与当前最小值的差(当前元素没有入栈的时候的最小值)。
这样我们pop和top的时候拿到栈顶元素再加上**上一个**最小值即可。
另外我们在push和pop的时候去更新min这样getMin的时候就简单了直接返回min。
> 注意上面加粗的“上一个”,不是“当前的最小值”
经过上面的分析问题的关键转化为“如何求得上一个最小值”解决这个的关键点在于利用min。
pop或者top的时候
- 如果栈顶元素小于0说明栈顶是当前最小的元素它出栈会对min造成影响我们需要去更新min。
上一个最小的是“min - 栈顶元素”,我们需要将上一个最小值更新为当前的最小值
> 因为栈顶元素入栈的时候的通过 `栈顶元素 = 真实值 - 上一个最小的元素` 得到的,
而真实值 = min 因此可以得出`上一个最小的元素 = 真实值 -栈顶元素`
- 如果栈顶元素大于0说明它对最小值`没有影响`,上一个最小值就是上上个最小值。
![](https://pic.leetcode-cn.com/7da0473d92d70bb47ce7b62303c062e5f517b09d1bf501c4ad341b65415d5c43.jpg)
![](https://pic.leetcode-cn.com/aefec54238c942c484837ea6c724304fb179d3d64f110481d955d9eea65c4fc5.jpg)
## 关键点
- 最小栈存储的不应该是真实值而是真实值和min的差值
- top的时候涉及到对数据的还原这里千万注意是**上一个**最小值
## 代码
* 语言支持JSPython
Javascript Code:
```js
/*
* @lc app=leetcode id=155 lang=javascript
*
* [155] Min Stack
*/
/**
* initialize your data structure here.
*/
var MinStack = function() {
this.stack = [];
this.minV = Number.MAX_VALUE;
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
// update 'min'
const minV = this.minV;
if (x < this.minV) {
this.minV = x;
}
return this.stack.push(x - minV);
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
const item = this.stack.pop();
const minV = this.minV;
if (item < 0) {
this.minV = minV - item;
return minV;
}
return item + minV;
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
const item = this.stack[this.stack.length - 1];
const minV = this.minV;
if (item < 0) {
return minV;
}
return item + minV;
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
return this.minV;
};
/**
* Your MinStack object will be instantiated and called as such:
* var obj = new MinStack()
* obj.push(x)
* obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.min()
*/
```
Python Code:
```python
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 min(self) -> int:
return self.minV
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()
```
**复杂度分析**
- 时间复杂度O(1)
- 空间复杂度O(1)
# 两个栈
## 思路
我们使用两个栈:
- 一个栈存放全部的元素pushpop都是正常操作这个正常栈。
- 另一个存放最小栈。 每次push如果比最小栈的栈顶还小我们就push进最小栈否则不操作
- 每次pop的时候我们都判断其是否和最小栈栈顶元素相同如果相同那么我们pop掉最小栈的栈顶元素即可
## 关键点
- 往minstack中 push的判断条件。 应该是stack为空或者x小于等于minstack栈顶元素
## 代码
JavaScript
```js
/**
* initialize your data structure here.
*/
var MinStack = function() {
this.stack = []
this.minStack = []
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
this.stack.push(x)
if (this.minStack.length == 0 || x <= this.minStack[this.minStack.length - 1]) {
this.minStack.push(x)
}
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
const x = this.stack.pop()
if (x !== void 0 && x === this.minStack[this.minStack.length - 1]) {
this.minStack.pop()
}
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
return this.stack[this.stack.length - 1]
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
return this.minStack[this.minStack.length - 1]
};
/**
* Your MinStack object will be instantiated and called as such:
* var obj = new MinStack()
* obj.push(x)
* obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.min()
*/
```
Python3:
```python
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
self.minstack = []
def push(self, x: int) -> None:
self.stack.append(x)
if not self.minstack or x <= self.minstack[-1]:
self.minstack.append(x)
def pop(self) -> None:
tmp = self.stack.pop()
if tmp == self.minstack[-1]:
self.minstack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
return self.minstack[-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.min()
```
**复杂度分析**
- 时间复杂度O(1)
- 空间复杂度O(N)