描述
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素
示例
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
解题思路
题目重点
在检索最小元素时,算法时间复杂度需要是常数时间(O(1));那么就需要在存储数据的时候,就要把最小元素存储起来。
针对这点,在设计数据结构时就有以下几种思路:
1: 使用两个列表或者数组,分别存储存储的元素以及插入当前元素时存在的最小元素相关信息(例如:最小元素的下标或者最小元素本身)【需要两个数据结构或者一个数据结构将数据交叉存储】
2: 创建一个元素类,将当前存储的元素和最小元素作为内部变量;再使用数据结构存储元素类的变量【需要一个数据结构,结构可能看起来更加简明】
3: 使用栈来存储当前存入的元素,只不过需要将插入元素和当前的最小值交叉存储【最简单的一种方式】
代码实现
1:分别存储插入元素和当前最小元素
public class MinStack {
public static void main(String[] args) {
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
System.out.println("min: "+minStack.getMin());
minStack.pop();
System.out.println("top: "+minStack.top());
System.out.println("min: "+minStack.getMin());
}
private int mNum;
private int mMin;
private int mMinIndex;
private List<Integer> list;
private List<Integer> mMinIndexs;
public MinStack() {
list = new ArrayList<>();
mMinIndexs = new ArrayList<>();
}
public void push(int x) {
mNum ++;
list.add(x);
if (mNum == 1) {
mMin = x;
mMinIndex = 0;
} else {
if (x > mMin) {
} else {
mMin = x;
mMinIndex = mNum - 1;
}
}
mMinIndexs.add(mMinIndex);
}
public void pop() {
if (mNum > 0) {
list.remove(mNum - 1);
mMinIndexs.remove(mNum - 1);
mNum --;
if (mNum > 0) {
mMinIndex = mMinIndexs.get(mNum - 1);
mMin = list.get(mMinIndexs.get(mMinIndex));
} else {
mMin = 0;
mMinIndex = 0;
}
}
}
public int top() {
if (mNum > 0) {
return list.get(mNum - 1);
}
return Integer.MIN_VALUE;
}
public int getMin() {
if (mNum > 0) {
return list.get(mMinIndexs.get(mNum - 1));
}
return Integer.MIN_VALUE;
}
}
在上边的代码中需要分别维护两个list,操作稍显复杂。
2:创建一个元素类
public class MinStack {
public static void main(String[] args) {
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
System.out.println("min: "+minStack.getMin());
minStack.pop();
System.out.println("top: "+minStack.top());
System.out.println("min: "+minStack.getMin());
}
private int mMin = Integer.MAX_VALUE;
private List<Element> list;
public MinStack() {
list = new ArrayList<>();
}
public void push(int x) {
Element element = new Element();
element.item = x;
if (x > mMin) {
element.minItem = mMin;
} else {
element.minItem = x;
mMin = x;
}
list.add(element);
}
public void pop() {
if (list != null && !list.isEmpty()) {
list.remove(list.size() - 1);
}
if (list.isEmpty()) {
mMin = Integer.MAX_VALUE;
} else {
mMin = list.get(list.size() - 1).minItem;
}
}
public int top() {
if (list != null && !list.isEmpty()) {
return list.get(list.size() - 1).item;
}
return Integer.MIN_VALUE;
}
public int getMin() {
if (list != null && !list.isEmpty()) {
return list.get(list.size() - 1).minItem;
}
return Integer.MIN_VALUE;
}
private class Element{
public int item;
public int minItem;
}
}
在方法二中代码稍微比方法一的简洁易懂一些
使用栈存储
这种实现的方式比较简单,这里不再使用代码实现;只是提供一种思路
总结
在上边两种方法中一定要注意在 pop() 方法中一定要将 mMin 重新赋值为列表的最后一个元素。
因为这个原因导致在验证代码的时候出了几次问题