题目描述
解法一:辅助栈法
普通栈的 push() 和 pop() 函数的复杂度为 O(1) ;而获取栈最小值 min() 函数需要遍历整个栈,复杂度为 O(N) 。为了将 min() 函数复杂度降为 O(1),可通过建立辅助栈实现。
Java
class MinStack {
// stack继承vector,是线程安全的,会增加额外开销,可以用普通的ArrayList或LinkedList实现
LinkedList<Integer> stack1, stack2;
/** initialize your data structure here. */
public MinStack() {
stack1 = new LinkedList<> ();
stack2 = new LinkedList<> (); // 辅助栈,栈顶元素始终保存当前栈中最小值
}
public void push(int x) {
stack1.addFirst(x);
if (stack2.size()==0 || stack2.peek()>x) // 若辅助栈为空,或新压栈元素小于当前辅助栈的栈顶元素,即最小值变了
stack2.addFirst(x);
else // 否则,辅助栈继续压入当前最小值
stack2.addFirst(stack2.peek());
}
public void pop() {
stack1.removeFirst();
stack2.removeFirst(); // 每次有元素出栈时,同时弹出辅助栈的栈顶元素,此时新栈顶元素即为下一个最小值
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();
}
}
另一种写法:
辅助栈中不一定要保持和数据栈一样的长度,只需要存储所有非严格降序的元素,即辅助栈的栈顶元素始终对应数据栈的最小值即可。当最小元素从数据栈中被弹出时,辅助栈也同时弹出该最小值,此时辅助栈中新的栈顶元素即为下一个最小元素。
class MinStack {
private LinkedList<Integer> stack1, stack2;
/** initialize your data structure here. */
public MinStack() {
stack1 = new LinkedList<> (); // 数据栈
stack2 = new LinkedList<> (); // 辅助栈
}
public void push(int x) {
stack1.addFirst(x);
// 若辅助栈为空或新入栈元素小于当前辅助栈的栈顶元素(即最小值),则压入辅助栈
if (stack2.size() == 0 || x <= stack2.peek())
stack2.addFirst(x);
}
public void pop() {
int tmp = stack1.removeFirst();
// 当最小元素从数据栈中被弹出时,辅助栈也同时弹出该最小值
if (tmp == stack2.peek())
stack2.removeFirst();
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();
}
}
复杂度分析:
时间复杂度: O(1),push(), pop(), top(), min() 四个函数的时间复杂度均为常数级别。
空间复杂度: O(N),当共有 N 个待入栈元素且依次递减时,辅助栈最差情况下要存储这 N 个元素,使用 O(N) 额外空间。
解法二:无辅助栈法
维护一个变量 min,动态更新,时刻记录下当前数据栈中的最小元素。
值得注意的是:如果当前的最小元素被弹出了,我们需要将 min 变量更新为数据栈中的次小元素,如何在 O(1)的时间内找到这个次小元素呢,也就是说要求在不需要再遍历一遍剩余的元素的前提下找到次小元素,为了解决这个问题,我们可以在每次压栈的时候做一下判断,如果待压栈的新元素小于等于当前最小元素,则先压入一个当前最小值,再压入新元素!注意判断条件是小于等于,因为当最小元素出栈时,我们是要执行两次出栈操作的以便获取次小元素,因此压栈的时候即便新元素是等于当前最小元素,也要压栈两次,这样才能保证后续操作不出错。
Java
class MinStack {
LinkedList<Integer> stack;
int min;
/** initialize your data structure here. */
public MinStack() {
stack = new LinkedList<>();
min = Integer.MAX_VALUE;
}
public void push(int x) {
if (x <= min) { // 如果待压栈的新元素小于等于当前最小元素,则先压入一个当前最小值
stack.addFirst(min);
min = x; // 更新最小值
}
stack.addFirst(x); // 再压入新元素
}
public void pop() {
if (stack.removeFirst() == min) // 如果当前最小元素被弹出栈了,更新 min为次小元素
min = stack.removeFirst();
}
public int top() {
return stack.peek();
}
public int min() {
return min;
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.min();
*/
参考
https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/solution/mian-shi-ti-30-bao-han-minhan-shu-de-zhan-fu-zhu-z/