题目:定义栈的数据结构,请在该类型中实现一个可以获得栈的最小元素的min函数。在该栈中,调用min,push及pop的时间复杂度都是O(1).java
看到这个问题,咱们的第一反应多是每次压入一个新元素进栈时,将栈里的全部元素排序,让最小的元素位于栈顶,这样就能在O(1)时间获得最小元素了。但这种思路不能保证最后压入的元素可以最早出栈,所以这个数据结构已经不是栈了。node
咱们接着想到在栈里添加一个成员变量存放最小的元素。每次压入一个新元素进栈的时候,若是该元素比当前最小的元素还要小,则更新最小元素。面试官听到这种思路以后就会问:若是当前最小的元素被弹出栈了,如何获得下一个最小的元素呢?面试
分析到这里咱们发现仅仅添加一个成员变量存放最小元素是不够的,也就是说当最小元素弹出栈的时候,咱们但愿可以获得次小元素。所以在压入这个最小元素以前,咱们要把次小元素保存起来。所以,在压入这个最小元素以前,咱们要把次小元素保存起来。数据结构
是否是能够把每次的最小元素都保存起来,放在另一个辅助栈里呢?咱们不妨举几个例子来分析一下把元素压入或者弹出栈的过程。函数
题关键在于用辅助栈储存什么值。要保证辅助栈的top是最小值,pop以后的顶部仍然是最小值。也就是说辅助栈从上到下存储的应该是最小值->次小值->次次小值……排序
这里容易进入一个误区就是:难道辅助栈就是对数据栈的排序?若是真是这样,push的时候由于要排序不能知足O(1);数据栈pop的时候,辅助栈要先查找数据栈pop出去的值而后再pop,也不知足O(1)。class
当两个栈为空时,push进去的第一个值即为最小值;import
push第二个元素时,若push的值<辅助栈顶元素(此处即第一个值),则将此值压进辅助栈;若push的值大于等于辅助栈顶元素,则将辅助栈顶元素再次push进去。变量
pop的时候,数据栈辅助栈均弹出顶元素。im
实现代码以下:
package cglib;
import java.util.Stack;
public class DeleteNode {
Stack<Integer> stack1 = new Stack<Integer>(); // 数据栈
Stack<Integer> stack2 = new Stack<Integer>(); // 辅助栈 用于返回min值
public void push(int node) {
stack1.push(node);
if (stack2.empty()) {
stack2.push(node);
} else {
if (node < stack2.peek().intValue())//若是进入的数小于辅助栈的栈顶元素
stack2.push(node);//则放进去进入的数
else stack2.push(stack2.peek());//不然放进辅助栈的栈顶元素
}
}
@SuppressWarnings("null")
public int pop() {
if(stack1.empty()||stack2.empty()){
return (Integer) null;
}
stack2.pop();
return stack1.pop();
}
public int top() {
if (!stack1.empty())
return stack1.peek().intValue();
else return 0;
}
public int min() {
if (!stack2.empty())
return stack2.peek().intValue();
else return 0;
}
public static void main(String[] args) {
DeleteNode ms = new DeleteNode();
ms.push(4);
ms.push(3);
ms.push(1);
ms.push(5);
ms.push(2);//4,3,1,5,2
//System.out.println("pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
}
}
输出:
min:1 pop:2 min:1 pop:5 min:1 pop:1 min:3 pop:3