这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
最小栈(题号155)
题目
设计一个支持 push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
push(x)
—— 将元素x
推入栈中。pop()
—— 删除栈顶的元素。top()
—— 获取栈顶元素。getMin()
—— 检索栈中的最小元素。
示例:
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
提示:
pop
、top
和getMin
操作总是在 非空栈 上调用。
链接
解释
这题啊,这题是简我击失败了。
面试中被问到了,结果没答出来啊~
如果正常刷题的话是没问题啊,结果面试时不知道是不是因为太紧张,一点思路都没有,最后还是在面试官的提醒下答出来的。
当时怎么想都是O(n)
的时间复杂度啊,O(1)
是真的想不出来。
O(n)
其实很好操作,直接用Math.min
直接取最小值即可,这没啥可说的。
O(1)
的话就得考虑到最小元素的获取时机了。
先将这个问题拆解下,如果想在getMin
时变成O(1)
,那么证明获取最小数字的位置应该在push
或者pop
,那总不能在push
和pop
时都执行下Math.min
吧,这样虽然让getMin
强行O(1)
了,但是其本质上没有变化,还是O(n)
的时间复杂度。
其实这题的根源就在于push
操作,要做的也很简单,在每次push
的情况下记录当前的最小数字,下一次push
的时候拿当前的值来和上一次push
的最小值进行比较,然后记录当前位置的最小值即可。
pop
操作单纯取出数组的最后一个元素即可,别的没有任何的多余操作了,需要做的只是维护一个变量,这个变量可以是数组,也可以是对象,每次只需要取出上一个长度的最小值,然后更新当前长度的最小值。
想明白之后真的非常简单,可惜当时没想出来,唉~
自己的答案
var MinStack = function() {
this.x_stack = [];
this.min_stack = [Infinity];
};
MinStack.prototype.push = function(x) {
this.x_stack.push(x);
this.min_stack.push(Math.min(this.min_stack[this.min_stack.length - 1], x));
};
MinStack.prototype.pop = function() {
this.x_stack.pop();
this.min_stack.pop();
};
MinStack.prototype.top = function() {
return this.x_stack[this.x_stack.length - 1];
};
MinStack.prototype.getMin = function() {
return this.min_stack[this.min_stack.length - 1];
};
整体思路就是这样,在MinStack
内部需要再维持一个数组用来记录当前位置的最小值,push
的时候往min_stack
中推入一个新元素,这个元素是min_stack
的最后一个元素和当前插入值的最小值;pop
的时候需要去掉x_stack
的最后一个元素和min_stack
的最后一个元素,籍此来保持min_stack
的最后一个元素一直都是最新最小值;top
直接取x_stack
的最后一个元素;getMin
取min_stack
的最后一个元素即可。
典型的用空间换时间,没想出来真是可惜了
更好的方法
无
PS:想查看往期文章和题目可以点击下面的链接:
这里是按照日期分类的👇
经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇