设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
- push(x) —— 将元素 x 推入栈中。
- pop() —— 删除栈顶的元素。
- top() —— 获取栈顶元素。
- getMin() —— 检索栈中的最小元素。
方法一:使用辅助堆栈
思路:
- 借用一个辅助栈 因为TS中没有栈,所以用数组代替,用于存获取stack中最小值。
- push()方法: 每当push()新值进来时,如果 小于等于 helpArr 栈顶值,则一起push()到 helpArr,即更新了栈顶最小值;
- ()方法: 判断将pop()出去的元素值是否是min_stack栈顶元素值(即最小值),如果是则将 helpArr栈顶元素一起pop(),这样可以保证 helpArr 栈顶元素始终是stack中的最小值。
- getMin()方法: 返回 helpArr 栈顶即可。
- helpArr 等价于遍历stack所有元素,把升序的数字都删除掉,留下一个从栈底到栈顶降序的栈。
- 相当于给stack中的降序元素做了标记,每当pop()这些降序元素,helpArr 会将相应的栈顶元素pop()出去,保证其栈顶元素始终是stack中的最小元素。
- 复杂度分析:
(1)时间复杂度 O(1)O(1) :压栈,出栈,获取最小值的时间复杂度都为 O(1)O(1) 。
(2)空间复杂度 O(N)O(N) :包含 N、N 个元素辅助栈占用线性大小的额外空间。
class MinStack {
constructor() {
this.stackArr = [];
this.helpArr = [];
}
protected stackArr: number[];
protected helpArr: number[];
push(val: number): void {
this.stackArr.push(val);
if(!this.helpArr.length) {
this.helpArr.push(val);
} else {
let lastMinNum = this.helpArr[this.helpArr.length-1];
if(val >= lastMinNum) {
this.helpArr.push(this.helpArr[this.helpArr.length-1]);
} else {
this.helpArr.push(val);
}
}
}
pop(): void {
if(this.stackArr.length) {
this.stackArr.pop();
}
if(this.helpArr.length) {
this.helpArr.pop();
}
}
top(): number {
if(this.stackArr.length) {
return this.stackArr[this.stackArr.length-1];
} else {
return null;
}
}
getMin(): number {
if(this.helpArr.length) {
return this.helpArr[this.helpArr.length-1];
}
else {
return null;
}
}
}
/**
* Your MinStack object will be instantiated and called as such:
* var obj = new MinStack()
* obj.push(val)
* obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.getMin()
*/
方法二:使用一个堆栈实现
经过之后的查阅资料等得知,还有一种可以仅仅使用一个堆栈即可实现的方法(也就是空间复杂度)
思路:
- 栈中压入的是需要压栈的值和最小值的差值
class MinStack {
constructor() {
this.stackArr = [];
this.min = 9999;
}
protected stackArr: number[];
protected min: number;
push(val: number): void {
if (!this.stackArr.length) {
//因为最开始栈内是空的所以最小值就是 val ,入栈为 0
this.stackArr.push(0);
this.min = val;
} else {
//入栈的值和最小值的差值
this.stackArr.push(val - this.min);
if (val < this.min)
this.min = val;
}
}
pop() {
if (!this.stackArr.length)
return;
let pop = this.stackArr.pop();
//因为入栈的是差值,当出栈的为负数的时候,说明栈中最小值已经出栈了,
//这里要重新更新最小值
if (pop < 0)
this.min -= pop;
}
top(): number {
let top = this.stackArr[this.stackArr.length-1];
if (top > 0) {
//栈顶元素如果是正的,说明栈顶元素压栈的时候是比栈中最小值大的,根据
//top=x - min,可以计算x=top+min
return top + this.min;
} else {
//当栈顶元素是负数的时候,说明栈顶元素压栈的时候是比栈中最小值小的,
//而压栈完之后他会更新最小值min,所以如果在使用上面公式肯定是不行
//的。如果栈顶元素压栈的时候比最小值小,他会更新最小值,这个最小值
//就是我们要压栈的值,所以这里直接返回min就行了。
return this.min;
}
}
getMin(): number {
return this.min;
}
}
/**
* Your MinStack object will be instantiated and called as such:
* var obj = new MinStack()
* obj.push(val)
* obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.getMin()
*/lse {
return null;
}
}
}
/**
* Your MinStack object will be instantiated and called as such:
* var obj = new MinStack()
* obj.push(val)
* obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.getMin()
*/