一、需求
- 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.
二、辅助栈法
2.1 思路分析
- 普通栈的push与pop函数时间复杂度为O(1),而获取栈的最小值min()函数需要遍历整个栈,时间复杂度为O(N);
- 若将min()函数的降低为O(1),那么需要设置辅助栈:
数据栈A:栈A用于存储元素;
数据栈B:栈B用于存储栈A中所有非严格降序的元素,则栈A中的最小原始终对应栈B的栈顶元素,即min()函数只需要返回 栈B的栈顶元素即可。
3.函数设计:
(1)push(x)函数:重点维护栈B的非严格降序
1.将元素x压入到栈A;
2.若栈B为空或者x小于等于(如果只是小于,那么栈A中的重复的最小元素出栈时,会导致栈B空栈异常)栈B的栈顶元素,那么将x压入栈B;
(2)pop()函数:重点保证栈A和栈B的元素一致性
1.执行栈A出栈,出栈元素记为y;
2.若y等于栈B的栈顶元素,说明最小元素出栈了,要更新栈B,则将执行栈B出栈。
(3)top()函数:直接返回A的栈顶元素。
(4)min()函数:直接返回B的栈顶元素。
2.2 代码实现
class MinStack {
/** initialize your data structure here. */
Stack<Integer> A;
Stack<Integer> B;
public MinStack() {
A = new Stack<Integer>();
B = new Stack<Integer>();
}
public void push(int x) {
A.add(x);
if(B.isEmpty() || x <= B.peek()) {
B.add(x);
}
}
public void pop() {
if(A.pop().equals(B.peek())) {
B.pop();
}
}
public int top() {
return A.peek();
}
public int min() {
return B.peek();
}
}
/**
* 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();
*/
2.3 复杂度分析
- 时间复杂度为O(1),四个函数的时间复杂度均为常数级别;
- 空间复杂度为O(N),其中N为待入栈的元素。
三、链表法
3.1 思路分析
- 写一个链表类,其成员包括val、min、next,分别是当前节点的值、链表中节点最小值、指向下一个节点的指针;
- push方法:不断增加链表节点(按照...③--->②--->①--->null的方式从右向左添加节点)且更新最小值的过程;
- pop方法:根据2,容易得出只需将head节点后移到下一个节点;
- min方法:返回链表的成员min的值;
3.2 代码实现
class Node {
int val;
int min;
Node next;
public Node(int val, int min, Node next) {
this.val = val;
this.min = min;
this.next = next;
}
}
class MinStack {
Node head;
/** initialize your data structure here. */
public MinStack() {
}
public void push(int x) {
if(head == null) {
head = new Node(x, x, null);
} else {
head = new Node(x, Math.min(x, head.min), head);
}
}
public void pop() {
head = head.next;
}
public int top() {
return head.val;
}
public int min() {
return head.min;
}
}
3.3 复杂度分析
- 时间复杂度为O(1),四个函数的时间复杂度均为常数级别;
- 空间复杂度为O(N),其中N为链表的节点数。
四、学习地址
作者:Krahets