思路:
push,pop操作在常量時間複雜度內完成,沒有問題,但是,min操作需要在常量時間複雜度內完成,一開始很容易想到在棧中儲存一個變數min,用來儲存最小值,那麼如果需要min()操作時,只需要查min變數的值即可.這個思路看起來不錯,但是,有一個致命的缺陷,那就只是,如果只儲存一個min變數,那麼當min也需要彈棧的時候,那麼棧中的min也需要用次二小的值更新,但是,此時無法知道第二個小值是哪個 ,我們也可以試圖儲存第二小的變數secMin,當最小值彈棧的時候,我們就用secMin去更新min變數,但是,此時,secMin若出棧也應該需要ThirdMin更新才行,如果ThirdMin也出棧.......這樣下去,我們就需要儲存min,secMin,ThirdMin......等所有小值.因此用o(1)個變數的辦法顯然無法滿足.
現在的問題變成了,我們需要一個額外的空間來儲存當前的最小值,即使當前的最小值出棧了,我們依然可以得到最新當前的最小值(無論彈棧,壓棧的過程如何變化),
我們可以嘗試用輔助棧的辦法來解決:
在新定義的棧中儲存一個資料棧和一個輔助棧.輔助棧棧頂儲存的是當前的最小值min.
min()操作時:只需要查輔助棧頂元素
push( _val )操作時:先將_val壓入資料棧,再比較_val和輔助棧頂元素Top,如果_val <= Top,則_val壓進輔助棧,使得_val成為當前的最小值,注意,_val==top也需要入棧.
pop()操作時:先將資料棧頂元素彈棧,如果棧頂元素是最小值,彈了輔助棧頂元素(彈出最小值min)
代碼如下:
#include<iostream>#include<stack>using namespace std;struct MinStack{private:stack<int> Data;stack<int> Min;public:void push(int val){Data.push(val);if(Min.empty() || val <= Min.top())Min.push(val);}int pop(){if(Data.empty()){cout<<"pop error"<<endl;throw "Error";}int Temp=Data.top();Data.pop();if(Temp == Min.top())Min.pop();return Temp;}int min(){if(Min.empty()){cout<<"No min"<<endl;throw "error!";}return Min.top();}};void main(){MinStack ms;ms.push(2);ms.push(2);ms.push(3);ms.pop();ms.pop();ms.pop();cout<<ms.min();}
上面的辦法是典型的空間換是時間的應用.我們可以有另外一種不需要額外的空間的辦法.棧本來的結構就可以使push,pop操作在o(1)時間內完成.現在,我們把精力放在min操作上.為了使min操作也可以在o(1)時間內完成,由於棧結構的限制,我們只能將min儲存在棧頂.但是,棧頂的元素應該是當前的元素,這樣我們的pop操作才能在o(1)時間內完成.但是,僅僅利用棧頂明顯無法完成.我們可以嘗試使用兩個位置,棧頂位置和棧頂的下一個位置,棧頂儲存的是當前的min值,則棧頂的下一個位置儲存的是當前_val
-min的值.那麼需要pop的時候,只需要彈出兩個元素,或加或減就可以完成.
具體操作:push(_val):若棧為空白,直接壓入一個元素兩次,若棧不空,則將棧頂元素替換為(_val-min)和當前最新最小值.
pop(),彈出兩個元素,根據(_val-min)的正負,決定加還是減算出棧頂元素
min(),直接從棧頂元素求得.
代碼:
#include<iostream>#include<stack>using namespace std;struct MinStack{private:stack<int> Data;public:void push(int val){if(Data.empty()){Data.push(val);Data.push(val);}else{int min=Data.top();Data.pop();Data.push(val-min);Data.push(val < min ? val : min);}}int pop(){if(Data.empty()){cout<<"Pop Error!"<<endl;exit(1);}int min = Data.top(); Data.pop();int secMin = Data.top(); Data.pop();//彈棧一彈彈兩個if (secMin < 0) //secMin< 0,說明彈出的是最小值,需要用次二小值更新棧頂{ Data.push(min - secMin); return min; } else { //彈出的不是最小值,則直接彈出棧,無需更新最小值if (!Data.empty()) { Data.push(min); return secMin + min; } return min; } }int Min(){if(Data.empty()){cout<<"Search Min Error!"<<endl;exit(1);}int min=Data.top();return min;}};void main(){MinStack ms;ms.pop();ms.pop();ms.pop();cout<<ms.Min();}