

设计一个支持 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 操作总是在 非空栈 上调用。
仅使用一个栈完成后续遍历。步骤如下:
难点在于如何判断栈顶节点是否有未访问的子节点。 如果判断方式不当,很可能会因为栈顶节点是上一个已出栈节点的父节点,而导致其节点反复入栈出栈陷入死循环。
可以增加一个变量或指针,用于指向前一个已经出栈的节点。
每次判断栈顶节点的时候只需要提前判断一次是否与上一个出栈节点是父子关系,是的话则继续出栈,否则回到上面的步骤1再进行入栈循环。
public class MinStack {
private Stack<int> _stack;
private Stack<int> _minStack;
/** initialize your data structure here. */
public MinStack() {
_stack = new Stack<int>();
_minStack = new Stack<int>();
}
public void Push(int val) {
_stack.Push(val);
if(_minStack.Count > 0)
_minStack.Push(Math.Min(val, _minStack.Peek()));
else
_minStack.Push(val);
}
public void Pop() {
_minStack.Pop();
_stack.Pop();
}
public int Top() {
return _stack.Peek();
}
public int GetMin() {
return _minStack.Peek();
}
}执行结果 执行通过
执行用时 132 ms, 在所有 Java 提交中击败了48.59%的用户
内存消耗 35.1 MB, 在所有 Java 提交中击败了15.82%的用户思路和算法 要做出这道题目,首先要理解栈结构先进后出的性质。
对于栈来说,如果一个元素 a 在入栈时,栈里有其它的元素 b, c, d,那么无论这个栈在之后经历了什么操作,只要 a 在栈中,b, c, d 就一定在栈中,因为在 a 被弹出之前,b, c, d 不会被弹出。
因此,在操作过程中的任意一个时刻,只要栈顶的元素是 a,那么我们就可以确定栈里面现在的元素一定是 a, b, c, d。
那么,我们可以在每个元素 a 入栈时把当前栈的最小值 m 存储起来。在这之后无论何时,如果栈顶元素是 a,我们就可以直接返回存储的最小值 m。

按照上面的思路,我们只需要设计一个数据结构,使得每个元素 a 与其相应的最小值 m 时刻保持一一对应。
因此我们可以使用一个辅助栈,与元素栈同步插入与删除,用于存储与每个元素对应的最小值。
class MinStack {
Deque<Integer> xStack;
Deque<Integer> minStack;
public MinStack() {
xStack = new LinkedList<Integer>();
minStack = new LinkedList<Integer>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int x) {
xStack.push(x);
minStack.push(Math.min(minStack.peek(), x));
}
public void pop() {
xStack.pop();
minStack.pop();
}
public int top() {
return xStack.peek();
}
public int getMin() {
return minStack.peek();
}
}执行结果 执行通过
执行用时 5 ms, 在所有 Java 提交中击败了78.78%的用户
内存消耗 39.8 MB, 在所有 Java 提交中击败了92.25%的用户