携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情
题目描述
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack()初始化堆栈对象。void push(int val)将元素val推入堆栈。void pop()删除堆栈顶部的元素。int top()获取堆栈顶部的元素。int getMin()获取堆栈中的最小元素。
示例 1:
输入:
["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.
解题思路
什么是栈
栈是一个后入先出(LIFO)的结构。就相当于一个单出口停车场,先进去的车辆被后进去的车辆堵住了,最先进去的车只能最后一个走,并且是等待后一个进来的车辆走了才能走。
怎么使用数组去模拟栈
一般来说,我们可以使用数组去模拟栈,栈的入栈操作,就相当于向数组的尾部插入元素,对应的就是数组的 push 操作;而栈的出栈操作,弹出的是栈的顶部元素,就相当于数组的 pop 操作;同时,栈的顶就相当于数组的最后一个元素,栈的底就是数组的第一个元素。
思路
原本我是打算使用一个数组去做这道题的,但是每次去调用 getMin 去找最小值的时候,都需要比较栈中的所有元素,查找最小值,时间复杂度是 O(n),而题目要求我们能在常数的时间复杂度里找到最小值。
那么什么是常数时间呢,简单来说,就是你的 查找效率不应该随着数据的变大而变大。
那么我们能不能多用一个成员变量 minValue,每次 push 都和这个 minValue 比较,如果新入栈的值比它小就更新 minValue。
原本我也是这么想的,但是后来发现,如果我出栈的时候,把最小值给弹出去了,那么我的 minValue 是不是就不准确了?
说了这么多,那么到底怎么样的数据结构,能满足题目的要求呢。
重置珍藏版思路
我们可以使用另一个数组来模拟栈,来记录每次入栈后,栈的最小值,这个栈也叫 辅助栈。
具体步骤如下:
- 初始化一个栈 stack, 一个辅助栈 minStack,都为空数组。
- 新元素 value 入栈的时候,stack 正常 push,同时比较 value 和 minStack 最后一个元素的大小,表示到当前 stack 的长度为止,栈中的最小值是谁。
- 出栈的时候,stack 和 minStack 都要出栈。看起来没什么差别,我们仔细看看:如果 stack 栈顶是最小值,那么 minStack 的栈顶元素也是最小值,它出栈之后,那么 stack 和 minStack 都要出栈,此时 minStack 的栈顶元素又是新的最小值了,刚刚的出栈没有影响。
题解
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];
};