題目:定義棧的資料結構,要求新增乙個
min函式,能夠得到棧的最小元素。要求函式
min、
push
以及pop
的時間複雜度都是
o(1)
。分析:這是去年google的一道面試題。
我看到這道題目時,第一反應就是每次push乙個新元素時,將棧裡所有逆序元素排序。這樣棧頂元素將是最小元素。但由於不能保證最後push進棧的元素最先出棧,這種思路設計的資料結構已經不是乙個棧了。
在棧裡新增乙個成員變數存放最小元素(或最小元素的位置)。每次push乙個新元素進棧的時候,如果該元素比當前的最小元素還要小,則更新最小元素。
乍一看這樣思路挺好的。但仔細一想,該思路存在乙個重要的問題:如果當前最小元素被pop出去,如何才能得到下乙個最小元素?
因此僅僅只新增乙個成員變數存放最小元素(或最小元素的位置)是不夠的。我們需要乙個輔助棧。每次push乙個新元素的時候,同時將最小元素(或最小元素的位置。考慮到棧元素的型別可能是複雜的資料結構,用最小元素的位置將能減少空間消耗)push到輔助棧中;每次pop乙個元素出棧的時候,同時pop輔助棧。
參考**:
1 #include 2 #include 34 template class
cstackwithmin58
virtual ~cstackwithmin(void
) {}
910 t& top(void
);11
const t& top(void) const;12
13void push(const t&value);
14void pop(void
);15
16const t& min(void) const;17
18private
:19 dequem_data; //
the elements of stack
20 dequem_minindex; //
the indices of minimum elements
21};
2223
//get the last element of mutable stack
24 template t& cstackwithmin::top()
2528
29//
get the last element of non-mutable stack
30 template const t& cstackwithmin::top() const
3134
35//
insert an elment at the end of stack
36 template void cstackwithmin::push(const t&value)
3751}52
53//
erease the element at the end of stack
54 template void cstackwithmin::pop()
5562
63//
get the minimum element of stack
64 template const t& cstackwithmin::min() const
65
舉個例子演示上述**的執行過程:
步驟 資料棧 輔助棧 最小值
1.push 3 3 0 3
2.push 4 3,4 0,0 3
3.push 2 3,4,2 0,0,2 2
4.push 1 3,4,2,1 0,0,2,3 1
5.pop 3,4,2 0,0,2 2
6.pop 3,4 0,0 3
7.push 0 3,4,0 0,0,2 0
討論:如果思路正確,編寫上述**不是一件很難的事情。但如果能注意一些細節無疑能在面試中加分。比如我在上面的**中做了如下的工作:
用模板類實現。如果別人的元素型別只是int型別,模板將能給面試官帶來好印象;
兩個版本的top函式。在很多類中,都需要提供const和非const版本的成員訪問函式;
min函式中assert。把**寫的盡量安全是每個軟體公司對程式設計師的要求;
新增一些注釋。注釋既能提高**的可讀性,又能增加**量,何樂而不為?
總之,在面試時如果時間允許,盡量把**寫的漂亮一些。說不定**中的幾個小亮點就能讓自己輕鬆拿到心儀的offer。
以上**何海濤部落格
後面回帖中,有人提出了乙個優化演算法,可以減小維護最小值的輔助空間。
除了題目要求的棧之外新開乙個棧,用來記錄最小值,每當在原棧中push資料後,與最小值棧中的棧頂元素比較,如果新值較小,則在最小值棧中push新值;否則再次push棧頂元素.
pop的時候,只要將最小值棧也pop一下就行了.
這樣,min函式只需要返回最小值棧的棧頂元素即可.
常規解空間上的乙個優化:
一般說來,最小值不會每次都需要更新,因此最小值棧裡面會有很多重複元素.因此乙個簡單的優化就是在新值只當<=原最小值時才 pushintomin,注意這個==的條件是不可少的,這是為了防止在pop的時候錯誤的pop最小值.pop的是, 當待pop值==最小值時popminstack, 其他時候不對最小值棧進行pop
下面說一種具有常數空間複雜度的方法:
在這個方法裡,只需要額外開乙個用於存放當前最小值的變數min即可.因此下面提到的push和pop操作都是對於題目中要求的棧來操作的,當然,這也是這個演算法裡唯一的棧.
設push的引數為v_push,pop的返回值為v_pop.
先說下整體思路:因為棧中所有元素的值都不會小於當其為棧頂元素時min函式的值,所以在棧中其實只需要儲存某元素比相應最小值大出來的值就可以 了.而對於最小值更新的位置,棧元素肯定為0,因此可以利用這個位置來儲存更多的資訊,在這裡是更新後前兩個最小值的差值,而這個值肯定是非正的.
根據上面的思路,push函式按照如下策略進行:
首先push (v_push-min),如果v_push < min,更新min為v_push.
相應的,pop函式按照如下策略進行(稱棧頂元素為top):
如果top >= 0, v_pop = min+top, 如果top < 0, v_pop = min,然後更新min為min-top.
顯然,對於min函式來說,只需要返回min空間的內容即可.
與張霄學長交流後,學長也講了乙個類似的方法:
push時候 如果 v_push >= min, v_push 直接入棧, 如果 v_push < min, 那麼入棧的是 2 * v_push - min, 然後 min = v_push. 出棧時, 如果棧頂的top >= min 直接出,如果 top < min 則出現異常,將min作為pop的返回值,另外需要還原前乙個最小值,方法是 min = 2 * min - top
其實這兩種方法在思路上是完全一樣的,只是學長提供的方法裡,棧中所有元素都比我的方法裡大v_push.不過,這種變化直接帶來的好處是,在不更 新最小值的情況下,壓棧值和出棧值都不需要額外的計算,在高階語言層面上,一次加減法運算比單純的賦值至少多了一次訪存操作和一次alu的運算,這樣估計 來我的方法耗時會是學長方法的2倍左右,雖然時間複雜度都是一樣的.
以上**anchor89
設計包含min函式的棧
本文 題目 定義棧的資料結構,要求新增乙個min函式,能夠得到棧的最小元素。要求函式min push以及pop的時間複雜度都是o 1 分析 這是去年google的一道面試題。我看到這道題目時,第一反應就是每次push乙個新元素時,將棧裡所有逆序元素排序。這樣棧頂元素將是最小元素。但由於不能保證最後p...
設計包含min函式的棧
定義棧的資料結構,要求新增乙個min函式,能夠得到棧的最小元素,要求函式min,push及pop的時間複雜度都是o 1 棧的資料結構包含兩個普通棧,乙個棧存資料,另乙個棧存最小值 或最小值的位置,如果用stl裡的棧,則不能存最小值的位置,因為stl裡的stack不支援下標索引訪問 cpp view ...
設計包含min函式的棧
題目 定義棧的資料結構,要求新增乙個min函式,能夠得到棧的最小元素。要求函式min push以及pop的時間複雜度都是o 1 注 這是06年一道google的面試題.先來說個常規解和他的乙個優化,常規解的時間複雜度符合要求,但需要線性的額外空間.常規解 參考 除了題目要求的棧之外新開乙個棧,用來記...