问题描述,实现一个栈,要求push,pop,min(返回最小值的操作)的时间复杂度为O(1)。

     


     思路1:模拟实现一个栈,在成员变量中一个int类型的变量,用来保存最小值,每当push一个数据,都将push的数据与变量中保存的数据进行对比,如果,push数据小于保存的值,那么就将最小值更新为push进来的数据,反之,则不用替换。假想push(2,3,4,1),那么最后保存的最小值是1,时间复杂度也将会是1,因为操作的次数为常数。但是这种思路是错误的,原因在于,pop数据的时候不会更新最小数据,试想上面的例子,将1 pop出去,那么最小的值就变成了2,可是变量里面还是1,没有更新数据导致程序逻辑错误。

     思路2:使用两个栈结构来维护两段内存,一个存储正常push的数据,一个存储最小数据。

那么,这么样就不用为更新最小数据而头疼。

    1.定义一个类似栈结构的结构体(当然可以实现为模板将会更加方便)

    typedef struct _stack
    {
    	_stack()
    		:_capacity(5)
    		, _size(0)
    	{
    		_array = new int[5];
    	}
    
    	~_stack()
    	{
    		if (_array)
    		{
    			delete[] _array;
    			_array = NULL;
    		}
    	}
    
    	int* _array;	//存储数据的数组
    	int _capacity;	//容量
    	int _size;	//有效数据
    }stack;

    2.定义一个类来管理两个结构体的对象

    class Stack
    {
    public:
    	Stack() 
    		:s()
    		, minstack()
    	{}
    
    	bool pop(int* e)
    	{
    		if (s._size == 0)
    		{
    			return false;
    		}
    			
    		int value = s._array[--s._size];
    
    		if (value == minstack._array[minstack._size - 1])
    		{
    			--minstack._size;
    		}
    		*e = value;
    
    		return true;
    	}
    
    	bool push(int value)
    	{
    		
    		if (s._size >= s._capacity)
    		{
    			s._capacity = s._capacity * 2;
    			int* tmp = new int[s._capacity];
    			int* cmp = new int[s._capacity];
    			for (int i = 0; i < s._size; i++)
    			{
    				tmp[i] = s._array[i];
    			}
    			for (int i = 0; i < minstack._size; i++)
    			{
    				cmp[i] = minstack._array[i];
    			}
    			delete[] s._array;
    			delete[] minstack._array;
    
    			s._array = tmp;
    			minstack._array = cmp;
    		}
    
    		/*	
    		if (s._size == s._capacity)
    		{
    			return false;
    		}
    			*/  
    		if (minstack._size == 0 || value <= minstack._array[minstack._size - 1])
    		{
    			minstack._array[minstack._size++] = value;
    		}
    
    		s._array[s._size++] = value;
    		return true;
    	}
    
    	bool min(int* pMin)
    	{
    		if (minstack._size == 0)
    		{
    			return false;
    		}
    
    		*pMin = minstack._array[minstack._size - 1];
    		return true;
    	}
    private:
    	stack s;      //用来维护正常数据栈
    	stack minstack;  //用来维护最小数据栈
    };

    3.push函数实现细节

1).s维护的内存,正常压入数据

2).minstack维护的内存,当minstack._size == 0的时候,压入第一个数据,当要压入第二个数据的时候,需要和minstack维护的栈的top数据进行比较,如果压入数据比当前minstack的top数据小,则压入,否则则不压入。

wKioL1cI4RXiU9qrAAAusiZ8_SM269.png    左边为s维护的栈结构,右边为minstack维护的栈结构


    4.pop函数的实现细节

1).首先由push会知道 s.top() >= minstack.top() 是恒成立的。

2).取到即将要被s栈即将要被pop出去的数据,用数据与minstack栈顶元素作比较,如果s.top() > minstack.top() 则只将s栈的栈顶元素pop出去而不用pop minstack的栈顶元素。如果s.top() == minstack.top(),则将s栈和minstack栈 的元素统统pop出去。

wKioL1cI6znzGUbOAAAwRKD8bNQ669.png

     5.min实现细节

1).返回minstack的栈顶元素

wKiom1cI6siA_KFFAAAsZSt-uts655.png

    6.测试用例

    void Test()
    {
    	Stack s;
    	s.push(9);
    	s.push(7);
    	s.push(10);
    	s.push(5);
    	s.push(8);
    	s.push(1);
    	cout << "压入序列9 7 10 5 8 1" << endl;
    	cout << "弹出序列" << endl;
    	int value;
    	while (s.pop(&value))
    	{
    		cout << "pop  " << value << "\t";
    		if (s.min(&value))
    			cout << "min value : " << value << endl;
    		else
    			cout << "there is no min value!" << endl;
    	}
    }

    以上就是本人在做本道面试题的一些想法,分享给大家。