题目:
设计一个支持 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:数组实现
/**
* 思路:
* 用数组实现stack
* current指向的是还没有值的位置
* push current下标不断移动。越界扩容
* pop 出栈栈顶元素:current-1
* top 获取栈顶元素:current-1
* getMin 记录最小值,遍历整个数组
*/
class MinStack {
int[] arr;
int current;
/** initialize your data structure here. */
public MinStack() {
arr = new int[16];
current=0;
}
public void push(int x) {
if (current>=arr.length)grow();
arr[current++]=x;
}
public void pop() {
arr[--current]=0;
}
public int top() {
return arr[current-1];
}
public int getMin() {
int min=arr[0];
for (int i=1;i<current;i++){
if (arr[i]<min)min=arr[i];
}
return min;
}
private void grow() {
int oldCapacity = arr.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
arr = Arrays.copyOf(arr, newCapacity);
}
}
解法2:链表实现
/**
* 思路:
* 用链表实现stack
* 链表中记录min
* push元素的时候,如果Node不存在,也就是第一个元素,最小值就他自己
* 如果Node存在,新节点加入到链表头,指向链表。比较当前这个节点的值和min,在当前节点记录下当前状态的最小值
* pop,当前的节点的下一个节点变成head,把当前节点赋值null,方便GC。(即使栈顶元素出栈,新的栈顶元素记录着当前状态的min值)
* top直接返回head.value
* getMin直接返回min
*/
class MinStack {
class Node{
int value;
Node next;
int min;
public Node(int value,int min){
this.value=value;
this.min=min;
}
}
Node head;
/** initialize your data structure here. */
public MinStack() {
}
public void push(int x) {
if (head==null){
head=new Node(x,x);
}else {
Node new_node=new Node(x,Math.min(x,head.min));
new_node.next=head;
head=new_node;
}
}
public void pop() {
if (head!=null) {
Node new_head = head.next;
head = null;
head = new_head;
}
}
public int top() {
if (head!=null)return head.value;
return -1;
}
public int getMin() {
if (head!=null)return head.min;
return -1;
}
}
解法3:2个栈
/**
* 思路:
* 用2个栈实现stack
* 一个正常的出入栈normal_stack,另外一个存放最小值min_stack
* push如果min_stack栈顶元素大于等于当前值,把当前值存入
* pop如果正常出栈的值和min_stack栈顶元素值一样,min_stack进行出栈操作
*/
class MinStack {
ArrayDeque<Integer> normal_stack;
ArrayDeque<Integer> min_stack;
/** initialize your data structure here. */
public MinStack() {
normal_stack=new ArrayDeque<>();
min_stack=new ArrayDeque<>();
}
public void push(int x) {
if (normal_stack.isEmpty())min_stack.push(x);
else {
if (min_stack.peek()>=x)min_stack.push(x);
}
normal_stack.push(x);
}
public void pop() {
// 不自动拆箱
// Integer pop = normal_stack.pop();
// Integer min = min_stack.peek();
// min.peek()获取的是地址值,不自动拆箱,没法和pop比较
// if (pop==min.peek())min_stack.pop();
// if (pop==min)min_stack.pop();
int pop = normal_stack.pop();
int min = min_stack.peek();
if (pop==min)min_stack.pop();
}
public int top() {
return normal_stack.peek();
}
public int getMin() {
return min_stack.peek();
}
}
解法4:1个栈(栈中存放差值)
/**
* 思路:
* 用1个栈实现stack
* 栈中存放peek=当前值x-min
* 入栈的时候如果x是一个负数就更新min为v
* 出栈的时候,如果是负数就用x(也就是现在的min)-v求出上一个min的值
* top的时候需要注意:如果栈中元素小于0(最小值),返回min。否则返回peek+min
*
* 注意:为了防止超出int的范围我们这里最后都设置成long
*/
class MinStack {
ArrayDeque<Long> stack;
long min;
/** initialize your data structure here. */
public MinStack() {
stack=new ArrayDeque<>();
}
public void push(int x) {
if (stack.isEmpty()){
min=x;
stack.push(0L);
}else {
long peek = x - min;
stack.push(peek);
if (peek<0)min=x;
}
}
public void pop() {
if (stack.isEmpty()) return;
if (stack.peek()<0)min=min-stack.pop();
else stack.pop();
}
public int top() {
Long peek = stack.peek();
if (peek<0)return (int) min;
else return (int) (peek+min);
}
public int getMin() {
return (int)min;
}
}
解法5:1个栈(当前值是最小值时存放2次)
/**
* 思路:
* 栈中记录2个最小值
* 入栈:如果入栈的当前值小于最小值min,先把min在入栈一次,之后更新min,之后在入栈当前值入栈。这样即使当前值出栈也可以找到之前的最小值min
* 出栈:如果出栈的是最小值,就需要更新最小值:在进行一次出栈,更新min
*/
class MinStack {
ArrayDeque<Integer> stack;
int min;
/** initialize your data structure here. */
public MinStack() {
stack=new ArrayDeque<>();
}
public void push(int x) {
if (stack.isEmpty()||x<=min){
stack.push(min);
min=x;
}
stack.push(x);
}
public void pop() {
if (stack.pop()==min)
min=stack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
}
解法6:1个栈(存放2个值,栈顶是最小值)
/**
* 思路:
* 入栈:先记录栈顶元素(之前的最小值)。再存放当前值,之后比较当前值和最小值,存放当前的最小值
* 出栈:出2次
* top:先出栈当前最小值,记录下来。之后获取栈顶元素,就是当前值。之后恢复栈(入栈最小值)
* getMin:栈顶元素就是最小值
*/
class MinStack {
ArrayDeque<Integer> stack;
/** initialize your data structure here. */
public MinStack() {
stack=new ArrayDeque<>();
}
public void push(int x) {
stack.push(x);
if (stack.isEmpty()){
stack.push(x);
}else {
Integer min = stack.peek();
stack.push(min>x?x:min);
}
}
public void pop() {
stack.pop();
stack.pop();
}
public int top() {
Integer pop = stack.pop();
Integer peek = stack.peek();
stack.push(pop);
return peek;
}
public int getMin() {
return stack.peek();
}
}