定义栈的数据结构,要求添加一个 min 函数,能够得到栈的最小元素。
要求函数 min、push 以及 pop 的时间复杂度都是 O(1)。
编程之美上有一道跟这个题比较类似的题目,但那道题是要实现函数 max、push 以及 pop 的时间复杂度都是 O(1)的一个队列,那个队列就是用本题中的栈组织成的。
思考如下:
首先想到的是在栈中设置一个成员变量为min,保存栈的最小元素。min的时间复杂度是o(1),push()的时候比较添加进的元素和min中的大小,更新min,时间复杂度也是o(1);但是在pop()的时候问题出现了,如果pop操作时把当前栈中最小值弹出栈了,只能遍历剩下的元素才能更新正确的min。
ok,问题来了。我们重新回顾一下推入栈的过程,假如当前栈的最小值是a,新加入栈的数是b,b<a,那么min=b;如果在某一次pop,a被pop出去了,那么栈的最小值就是b,也就是该元素将要添加进栈(还未添加进栈)的时候的最小值,我们需要保存一个变量才存储这个值的索引。
所以解决方法来了,在栈的元素的定义中,添加一个成员变量pre,它代表该元素将要添加进栈(还未添加进栈)的时候的最小值在栈中的位置。
在push过程,如果新的元素小于当前栈中最小值,pre设置为当前栈最小值的索引,更新栈中的minIndex和min;
如果新的元素大于当前栈中最小值,pre设置为当前栈最小值的索引..(其实pre不需要设置,因为在这种情况下这个元素的存在根本不影响min)
在pop过程,如果弹出的元素等于当前栈中最小值,将栈中的minIndex设置为弹出元素的preMin,更新栈中的min,弹出元素;
如果弹出的元素大于当前栈中最小值,直接弹出..
这个解决方法与设计模式中的备忘录模式有点相近,就是在每个元素中将之前栈的状况给保存起来,然后把元素push进栈;pop该元素的时候,通过里面的数据恢复该元素还未添加进栈的时候栈的状态..
关键代码:
栈元素定义:
class Element{
int data = 0; //数据
int preMin = 0; //未添加新元素的栈的最小值的索引
public Element(int data)
{
this.data = data;
}
}
栈的定义:
class Stack{
private int MAXSIZE = 10;
private Element[] elements = new Element[MAXSIZE];
private int pos = 0;
private int min = Integer.MAX_VALUE;
private int minIndex = 0;
public boolean push(int num)
{
if(pos >= MAXSIZE) //判断栈已满
{
System.out.println("栈已满!");
return false;
}
Element newE = new Element(num);
if(num < min) //push元素小于当前最小值,更新min;
{
min = num;
newE.preMin = minIndex;
minIndex = pos;
}
elements[pos] = newE;
pos++;
return true;
}
public boolean pop()
{
if(pos == 0)
{
System.out.println("栈为空!");
return false;
}
if(pos == minIndex+1) //当pop出当前最小值,更新min;
{
minIndex = elements[pos-1].preMin;
min = elements[minIndex].data;
}
pos--;
return true;
}
public int min() //min函数的定义:
{
if(pos == 0)
{
System.out.println("栈为空!");
return -1;
}
return min;
}
}