3.2 题目:
设计一个栈,除pop,push方法外,还支持min方法,要求这三个方法的时间复杂度为O(1)
解法:
1、第一种想法(X):
可以在栈类中加入一个minValue的字段,维护最小值。
入栈时,更新最小值;出栈时,也需要更新最小值。
若最小值被出栈,则需要搜索整个栈,才能找到新的最小值,这不符合O(1)的时间复杂度要求。
2、第二种想法(√):
按照空间换时间的思路,我们可以考虑每次新的元素入栈时,记录下该元素加入以后的新栈对应的最小值。这个最小值被维护在了这个新加入的元素中。
出栈的时候,不需要担心是否把最小值换出,只要找新栈顶维护的最小值即可。
min方法,也只需peek出栈顶元素,得到该元素的min字段即可。
举例说明:
push(5) 栈为{5} 最小值为5,这个最小值被存入了5这个元素对应的min字段中
push(6) 栈为{6,5} 最小值为5,这个最小值被存入了6这个元素对应的min字段中
push(3) 栈为{3,6,5} 最小值为3,这个最小值被存入了3这个元素对应的min字段中
push(7) 栈为{7,3,6,5} 最小值为3,这个最小值被存入了7这个元素对应的min字段中
pop() 弹出7,最小值为栈顶元素3维护的最小值 3
pop() 弹出3,最小值为栈顶元素6维护的最小值 5
......
3、第三种想法(√):
第二种想法有个缺点,当栈很大时,每个元素都要记录min,就会浪费大量的空间。
比如,假如最先入栈的元素是最小值3,后续入栈的元素都比这个值大,那么后续元素维护的最小值都是3,浪费空间。
可以使用另外一个新的栈Stack<Integer>来记录这个最小值,以节省空间,这个新的栈被维护到了StackWithMin这个栈中。
代码如下:
- package StackAndQueue;
- import java.util.Stack;
- public class StackWithMin extends Stack<Integer> {
- Stack<Integer> s2;
- public StackWithMin(){
- s2 = new Stack<Integer>();
- }
- public void push(int value){
- if(value <= min()){
- s2.push(value);
- }
- super.push(value);
- }
- public Integer pop(){
- int value = super.pop();
- if(value == min()){
- s2.pop();
- }
- return value;
- }
- public int min(){
- if(s2.isEmpty()){
- return Integer.MAX_VALUE;
- }
- else{
- return s2.peek();
- }
- }
- }
测试用例:
- @Test
- public void test_3_2() {
- StackWithMin stack = new StackWithMin();
- stack.push(3);
- System.out.println(stack.min());
- stack.push(4);
- System.out.println(stack.min());
- stack.push(5);
- System.out.println(stack.min());
- stack.push(6);
- System.out.println(stack.min());
- stack.pop();
- System.out.println(stack.min());
- stack.pop();
- System.out.println(stack.min());
- System.out.println();;
- while(!stack.s2.isEmpty()){
- System.out.println(stack.s2.pop());
- }
- }
测试结果:
第三种想法,只存了一个3到s2中
第二种想法,需要存4个3到每个元素中,对比之下,第三种想法更加节省空间。
在栈很大时,优势就很明显了