No2、设计包含 min 函数的栈(栈)


定义栈的数据结构,要求添加一个 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;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值