实现一个栈,要求push,pop,Min的操作时间复杂度为O(1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29503203/article/details/52507057

问题:实现一个栈,要求实现Push(入栈),Pop(出栈),Min(返回最小值)的操作时间复杂度为O(1).

分析:刚看到这个题的时候,用栈来实现Min(返回最小值)的操作,我的第一反应就是必须把栈中的最小值放在top()位置,然后根据栈的“后进先出”的道理来实现,但是问题接着就来了。首先,根据元素的不断push,最小值很有可能在不断更新啊,那么如何让最小值一直处于栈中top()位置呢?如果栈中为空或要压入的元素小于等于栈顶元素,那么这还好办,直接push进去就好了,在这里呢还有一个小问题,当我们要执行pop时,上一次的最小值就找不到了啊,所以呢,我们需要将其进行两次Push;如果我们遇到要Push的元素(d)大于栈顶元素,我们需要将栈中最小值先保存一份,在Push进元素d后再把这个最小值Push进去,由此就可以保证最小值一直处于top位置了。

下面是代码实现:

#include<assert.h>
#include<stack>
#include<iostream>
using namespace std;

template<typename T>
class Stack
{
public:
	void Push(const T& d)
	{
		//栈中为空或要压入的元素小于等于栈顶元素,则将该元素压入两次
		if(_s.empty() || d<=_s.top())    
		{
			_s.push(d);
                        _s.push(d);
		}
		else
		{
			T mindata=_s.top();     //先将最小值保存下来
			_s.push(d);
			_s.push(mindata);      //根据栈的“后进先出”的道理
		}
	}
	void Pop()
	{
		//对空栈pop操作非法
		assert(!_s.empty());
		_s.pop();               //在Push时保持了top()元素为最小值
		_s.pop();         

	}
	T& Min()
	{
		if(_s.empty())
		{
			cout<<"Search Min Error"<<endl;
			exit(1);
		}
		return _s.top();
	}
private:
	stack<T> _s;
};

void test()
{
	Stack<int> s;
	s.Push(9);
	s.Push(2);
	s.Push(6);
	s.Push(4);
	cout<<"min-value:"<<s.Min()<<endl;
	s.Pop();
}

int main()
{
	test();
	system("pause");
	return 0;
}


但是,对于这样的算法存在着一些缺陷:

比如:依次Push进1,2,3,4,……100,那么对最小值1的多份Push,会产生数据冗余,空间浪费就会很大,如下图:



还有一种方案是这样的:

用两个栈来实现,比如有两个栈s1,s2.    s1用来存放所有Push进的元素,s2用来作为辅助栈(每次压入s2的值都是s1中的最小值),如下图所示:



代码实现:

template<typename T>
class Stack
{
public:
	void Push(const T& d);
	void Pop();
	T& Min();
	T& Top();
private:
	stack<T> s;  //存放所有数据
	stack<T> min;  //存放较小数据
};
template<typename T>
void Stack<T>::Push(const T& d)
{
	s.push(d);
	if(min.empty() || d<=min.top())
	{
		min.push(d);
	}
}
template<typename T>
void Stack<T>::Pop()
{
	assert(!s.empty());
	if(s.top()==min.top())
	{
		min.pop();
	}
	s.pop();
}
template<typename T>
T& Stack<T>::Min()
{
	return min.top();
}
void test()
{
	Stack<int> s;
	s.Push(5);
	s.Push(3);
	s.Push(7);
	s.Push(2);
	s.Push(1);
	s.Push(1);
	s.Pop();
	cout<<s.Min()<<endl;
	s.Pop();
	cout<<s.Min()<<endl;
	s.Pop();
	cout<<s.Min()<<endl;
	s.Pop();
	cout<<s.Min()<<endl;
	s.Pop();
	cout<<s.Min()<<endl;
	s.Pop();
}

经过测试,入栈,出栈的顺序以及返回的最小值是一致的。

接着我们讨论以下的问题:

1.为什么push时的条件是d<=min.top(),而不是d<min.top()?

比如说:要push进5,3,7,2,1,1   最小值的栈如果只保存小于栈顶元素的值的话,那么就应该是5,3,2,1  当我们pop最小值栈时,整个栈的最小值变成2(返回min.top()),实际上其最小值依然为1.这就将导致返回最小值错误。

2.该题目的两种解决方案都是以空间换时间,那么如果没有时间复杂度的要求,该如何做到解决空间浪费的问题?

其实,这样很好办,我们先将push进去的元素排个序,保证最小值在栈顶,然后再进行pop,返回最小值的操作就很容易了。



展开阅读全文

没有更多推荐了,返回首页