程式設計師面試金典 - 面試題 03.02. 棧的最小值
阿新 • • 發佈:2021-01-12
題目難度: 簡單
今天繼續更新程式設計師面試金典系列, 大家在公眾號 演算法精選 裡回覆 面試金典 就能看到該系列當前連載的所有文章了, 記得關注哦~
題目描述
請設計一個棧,除了常規棧支援的 pop 與 push 函式以外,還支援 min 函式,該函式返回棧元素中的最小值。執行 push、pop 和 min 操作的時間複雜度必須為 O(1)。
示例:
- MinStack minStack = new MinStack();
- minStack.push(-2);
- minStack.push(0);
- minStack.push(-3);
- minStack.getMin(); --> 返回 -3.
- minStack.pop();
- minStack.top(); --> 返回 0.
- minStack.getMin(); --> 返回 -2.
題目思考
- 內部需要什麼資料結構來滿足所有操作都是 O(1), 一個棧夠嗎?
解決方案
思路
- 要使得 push 和 pop 的複雜度為 O(1), 傳統的棧就可以搞定, 難點在於如何使得 min 函式也為 O(1)
- 如果我們能一直維護當前所有元素的最小值, 那麼 min 函式直接返回它就可以, 但問題是在 pop 的時候有可能會正好 pop 這個最小值, pop 之後的最小值(也即原來的次小值)如何得到呢?
- 要儲存多個最小值, 顯然一個變數不夠用. 而根據上一步的分析, 這裡我們可以考慮額外引入一個單調遞減棧, 棧頂存當前最小值, 下面依次是次小, 第三小…
- 這樣如果 pop 了最小值的話, 這個單調棧的棧頂仍會儲存 pop 後的最小值, 每次 min 只需要取這個棧的棧頂即可
- 而 push 的時候也需要額外的操作, 由於是單調棧, 只需要在新的值小於等於棧頂的時候才 push 到單調棧中.特別注意在等於棧頂的時候也要 push 到單調棧中, 這是因為如果對於重複的最小值 x 不 push, 那麼在後續的 pop 其中一個 x 之後, 棧頂(不再是 x)就和實際最小值(仍為 x)不一致了
複雜度
- 時間複雜度
O(1)
- 各種操作都是常數複雜度
- 空間複雜度
O(N)
- 使用了兩個棧
程式碼
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
# 一個普通棧和一個單調遞減棧
self.minstack = []
self.stack = []
def push(self, x: int) -> None:
self.stack.append(x)
if not self.minstack or x <= self.minstack[-1]:
# 如果單調棧頂為空或者當前新值小於等於單調棧頂才push
# 注意這裡等於也需要push. 如果對於重複的最小值 x 不 push, 那麼在後續的 pop 其中一個 x 之後, 棧頂(不再是 x)就和實際最小值(仍為 x)不一致了
self.minstack.append(x)
def pop(self) -> None:
if not self.stack:
return
x = self.stack.pop()
if x == self.minstack[-1]:
# 如果單調棧頂恰好等於pop的值, 也要pop單調棧
self.minstack.pop()
def top(self) -> int:
if not self.stack:
return -1
return self.stack[-1]
def getMin(self) -> int:
if not self.minstack:
return -1
return self.minstack[-1]
大家可以在下面這些地方找到我~