栈与队列01:设计一个有getMin功能的栈

【题目】

实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。

 

【要求】

1:pop、push、getMin操作的时间复杂度都是O(1)。

2:设计的栈类型可以使用现成的栈结构。

 

【解答】

在设计时,我们使用两个栈,一个栈用来保存当前栈中的元素,其功能和一个正常的栈没有区别,这个栈记为stackData;另外一个栈用于保存每一步的最小值,这个栈记为stackMin。

 

【第一种设计方案】

(1)压入数据规则

假设当前数据为newNum,先将其压入stackData。然后判断stackMin是否为空:

  • 如果为空,则newNum也压入stackMin。
  • 如果不为空,则比较newNum和stackMin的栈顶元素中哪一个更小:

          a)如果newNum更小或者两者相等,则newNum也压入stackMin;

          b)如果stackMin中栈顶元素小,则stackMin不压入任何内容。

 

(2)弹出数据规则

        先在stackData中弹出栈顶元素,记为value。然后比较当前stackMin的栈顶元素和value哪一个更小。

        通过上文提到的压入规则可知,stackMin中存在的元素是从栈底到栈顶逐渐变小的,stackMin栈顶的元素既是stackMin栈的最小值,也是当前stackData栈的最小值。所以不会出现value比stackMin的栈顶元素更小的情况,value只可能大于或等于stackMin的栈顶元素。

        当value等于stackMin的栈顶元素时,stackMin弹出栈顶元素;当value大于stackMin的栈顶元素时,stackMin不弹出栈顶元素,返回value。

 

(3)查询当前栈中的最小值操作

        由上文的压入数据规则和弹出数据规则可知,stackMin始终记录着stackData中的最小值。所以,stackMin的栈顶元素始终是当前stackData中的最小值。

 

【代码实现1】

#include<stack>

class MyStack
{
private:
	std::stack<int> stackData;
	std::stack<int> stackMin;

public:
	virtual void push(int newNum){
		if (stackData.empty()){
			stackData.push(newNum);
		}
		else if (newNum <= getMin()){
			stackMin.push(newNum);
		}

		stackData.push(newNum);
	}

	virtual int pop(){
		if (stackData.empty){
			//抛出异常
		}

		int value = stackData.top();
		stackData.pop();
		if (value == getMin()){
			stackMin.pop();
		}
		return value;
	}

	virtual int getMin(){
		if (stackMin.empty()){
			//抛出异常
		}
		return stackMin.top();
	}
};

 

【第二种设计方案】

(1)压入数据规则

假设当前数据为newNum,先将其压入stackData。然后判断stackMin是否为空。如果为空,则newNum也压入stackMin;如果不为空,则比较newNum和stackMin的栈顶元素哪一个更小。

  • 如果newNum更小或者两者相等,则newNum也压入stackMin;
  • 如果stackMin中栈顶元素小,则把stackMin的栈顶元素重复压入stackMin,即在栈顶元素上再压入一个栈顶元素。

 

(2)弹出数据规则

在stackData中弹出数据;弹出stackMin中的栈顶。

 

(3)查询当前栈中的最小值操作

stackMin始终记录着stackData中的最小值,所以stackMin的栈顶元素始终是当前stackData的最小值。

 

【代码实现2】

class MyStack
{
private:
	std::stack<int> stackData;
	std::stack<int> stackMin;

public:
	virtual void push(int newNum){
		if (stackData.empty()){
			stackData.push(newNum);
		}
		else if (newNum < getMin()){
			stackMin.push(newNum);
		}
		else{
			int newMin = stackMin.top();
			stackMin.push(newMin);
		}
		stackData.push(newNum);
	}

	virtual int pop(){
		if (stackData.empty){
			//抛出异常
		}

		int value = stackData.top();
		stackData.pop();
		stackMin.pop();
		return value;
	}

	virtual int getMin(){
		if (stackMin.empty()){
			//抛出异常
		}
		return stackMin.top();
	}
};

 

【总结】

        方案一和方案二其实都是利用stackMin栈保存着stackData每一步的最小值。共同点是所有操作的时间复杂度都为O(1)、空间复杂度都为O(n)。区别是:方案一中stackMin压入时稍省空间,但是弹出操作稍费时间;方案中stackMin压入时稍费空间,但是弹出操作稍省时间。

 

【来源】

《程序员代码面试指南(IT名企算法与数据结构题目最优解)》左程云

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值