設計包含min函式的棧

2022-09-02 06:27:11 字數 3829 閱讀 2394

題目:定義棧的資料結構,要求新增乙個

min函式,能夠得到棧的最小元素。要求函式

min、

push

以及pop

的時間複雜度都是

o(1)

。分析:這是去年google的一道面試題。

我看到這道題目時,第一反應就是每次push乙個新元素時,將棧裡所有逆序元素排序。這樣棧頂元素將是最小元素。但由於不能保證最後push進棧的元素最先出棧,這種思路設計的資料結構已經不是乙個棧了。

在棧裡新增乙個成員變數存放最小元素(或最小元素的位置)。每次push乙個新元素進棧的時候,如果該元素比當前的最小元素還要小,則更新最小元素。

乍一看這樣思路挺好的。但仔細一想,該思路存在乙個重要的問題:如果當前最小元素被pop出去,如何才能得到下乙個最小元素?

因此僅僅只新增乙個成員變數存放最小元素(或最小元素的位置)是不夠的。我們需要乙個輔助棧。每次push乙個新元素的時候,同時將最小元素(或最小元素的位置。考慮到棧元素的型別可能是複雜的資料結構,用最小元素的位置將能減少空間消耗)push到輔助棧中;每次pop乙個元素出棧的時候,同時pop輔助棧。

參考**:

1 #include 2 #include 3

4 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的面試題.先來說個常規解和他的乙個優化,常規解的時間複雜度符合要求,但需要線性的額外空間.常規解 參考 除了題目要求的棧之外新開乙個棧,用來記...