經典面試題:設計包含min函式的棧,O(1)空間實現方法
題目:定義棧的資料結構,要求新增一個min函式,能夠得到棧的最小元素。要求函式min、push以及pop的時間複雜度都是O(1)。
注:這是06年一道Google的面試題.
先來說個常規解和他的一個優化,常規解的時間複雜度符合要求,但需要線性的額外空間.
除了題目要求的棧之外新開一個棧,用來記錄最小值,每當在原棧中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倍左右,雖然時間複雜度都是一樣的.