原题链接:点击
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
这是一道挺有意思的简单题,虽然对于我而言其设计思想和想法足以算上一个中等难度的题了…那么,开始吧,这次用 JavaScript 来写写,虽然JS这门语言坑比较多,但入坑之后也会发现十足的乐趣。伪面向对象走起,也算一个练习。
为了实现getMin
的常数级别的效率,栈是一种可以尝试的数据结构。利用一个名叫minStack
的辅助栈来保存当前遍历过的局部最小值,在push
过程中遇到不大于辅助栈栈顶的值时,继续将其压入辅助栈,仔细想想这其实就是局部搜索保存极小从而获取全局最小的一种策略(自己瞎掰的),需要注意的是在pop
弹出的时候需要比较原来的数据栈data
以及辅助栈minStack
的栈顶值,如果恰好弹出的是最小值,则一并弹出。代码如下:
// 辅助栈
class MinStack {
constructor(data=[], minStack=[]) {
this.data = data;
this.minStack = minStack;
}
push(x) {
this.data.push(x);
if (this.minStack.length === 0 || x <= this.minStack.slice(-1)) {
this.minStack.push(x);
}
}
pop() {
if (JSON.stringify(this.data.slice(-1)) === JSON.stringify(this.minStack.slice(-1))) {
this.minStack.pop();
}
this.data.pop();
}
top() {
return this.data.slice(-1);
}
getMin() {
return this.minStack.slice(-1);
}
};
为了在常数时间内获取最小值,额外的空间复杂度是必要的。上面开辟了一个新的辅助栈,用以保存极小值。那么试想也可以通过在push
数据的过程中携带极小值的信息入栈。具体而言就是push
两次,第一次push
原数据,第二次push
极小值,当然pop
的时候也需要两次,尽在当前数据栈下pop
一次即可得最小值,pop
第二次得到当前值。具体细节不作过多赘述。为此,写出如下代码:
class MinStack {
constructor(minStack=[]) {
this.minStack = minStack;
}
push(x) {
if (this.minStack.length === 0) {
this.minStack.push(x);
this.minStack.push(x);
} else {
let curMin = this.minStack.slice(-1);
this.minStack.push(x);
if (x < curMin) {
this.minStack.push(x);
} else {
this.minStack.push(curMin);
}
}
}
pop() {
this.minStack.pop();
this.minStack.pop();
}
top() {
return this.minStack.slice(-2)[0];
}
getMin() {
return this.minStack.slice(-1);
}
};
换一种思路,利用链表来保存最小值属性。
实话讲,下面的代码也是借鉴大佬然后转成javascript
来写的。但刚开始思索这道题的时候,我也确实尝试过用链表或二叉树等其他数据结构来解决,奈何力不从心。话不多说,代码如下:
// 一种链表的方法
class Node {
constructor(val, min, next=null) {
this.val = val;
this.min = min;
this.next = next;
}
}
class MinStack {
constructor() {
this.head = null
}
push(x) {
if (this.head === null) {
this.head = new Node(x, x)
} else {
this.head = new Node(x, Math.min(this.head.min, x), this.head);
}
}
pop() {
this.head = this.head.next;
}
top() {
return this.head.val;
}
getMin() {
return this.head.min;
}
};
这是一道简单题,哈哈,自己还是太菜…