目录
视频链接
栈的入门题目-最小栈
实现一个getmin方法(高效方法,即不用遍历),希望能实现O(1)
做法:准备两个栈
data和min栈
当我压入3时,我同步压入。
如果再加入个5,data栈压入5。让最小栈的栈顶和要压入的数比较。3<5,所以min栈再压入5。
比如再压入2,2现在是最小的,所以左右同时压入2。
比如再压入7,2目前还是最小的,所以左边压入7,右边压入2。
总结:就这三条逻辑
1)当前压的数字<=min栈的顶,当前数字压入min栈
2)当前压得数字>min栈的顶,min原来的数压入min栈
3)min栈为空,data为空,当前要压的数字压入min栈
为什么要这么做?
保证一一对应。即永远右边的栈顶是栈里元素的最小值。
要弹出的时候,data栈和min栈同步弹出就行
代码演示
import java.util.Stack;
public class MinStack1 {
//data栈:用于存放所有实际的数字
public Stack<Integer>data;
//min栈:辅助栈,其栈顶永远是当前data栈中的最小值
public Stack<Integer>min;
//构造方法:
public MinStack1(){
//初始化两个栈
data = new Stack<Integer>();
min = new Stack<Integer>();
}
/**
* 将一个元素推入栈中
*/
public void push(int val){
//第一步:无论如何,新元素val总是要被推入data栈
data.push(val);
//第二步:根据规则决定往min栈中推入什么
//条件一:min栈为空?(即这是第一个元素,它当然是最小值)
//条件二:val<=min.peek()? 如果是的话,那么目前val最小,val压入到min栈中。
//条件一条件二都是将val直接压入min栈中
if(min.isEmpty()||val<=min.peek()){
min.push(val);
}else{
//如果是条件三:即min.peek比val要小,那么再把它压一遍
min.push(min.peek());
}
}
/**
* 从栈中弹出一个元素
*/
public void pop(){
//data栈和min栈是严格同步的,所以data栈弹出时min栈也应该弹出,以维持同步
data.pop();
min.pop();
}
/**
* 查看栈顶元素
*/
public int top(){
//栈顶元素就是data栈的栈顶
return data.peek();
}
/**
* 获取栈的最小元素
*/
public int getMin() {
//即min的peek
return min.peek();
}
}
但这种方法(即用java自带的stack类效率低),所以我们选择用数组来亲手搭建一个栈,这样效率高。
public class MinStack2 {
//假设这个栈最多装8001个元素
public final int MAXN = 8001;
//用两个整型数组来代替stack类
public int[]data;//对应之前的data栈
public int[]min;//对应之前的min栈
//变量size:即表示当前元素的数量,也指向下一个要插入的位置
int size;
//构造方法
public MinStack2(){
//创建两个刚好能容纳MAXN个整数的数组
//相当于建好了两怕空的储物柜
data = new int[MAXN];
min = new int[MAXN ];
//初始时一个元素都没有所以size是0
size = 0;
}
/**
* 将一个元素推入我们用数组模拟的栈中
*/
public void push(int val){
//data[size] = val
//把新元素val放入data数组的第size个位置
//如果size是0,就放在data[0];如果size是1,就放在data[1]
data[size] = val;
//data栈压入之后,我们来想一想min栈怎么办(和上一题一样)
if(size == 0||val<=min[size-1]){
min[size] = val;
}else{
//否则,最小值不变
//复制上一个位置的最小值到当前位置,以保持和data数组的同步
min[size] = min[size-1];
}
//最重要的一步:把size加1,让指针指向下一个空位
//并且表示元素总数增加一个
size++;
}
/**
* 从我们用数组模拟的栈中弹出一个元素
*/
public void pop(){
//我们不需要真的去清除数组里的data[size-1]
//只需要把size减1,就等于我们逻辑上抛弃了最后一个元素
//下次push时,那个位置的值会被自然地覆盖掉
size--;
}
/**
* 查看栈顶元素
*/
public int top(){
//因为size指向地是下一个空位,所以栈真正地顶部元素位于它地前一个位置
// 即size-1
return data[size-1];
}
/**
* 获取栈中的最小元素
*/
public int getMin(){
//同理,最小元素即min数组的栈顶位置,也就是size-1
return min[size-1];
}
}