定義棧的資料結構,請在該型別中實現一個能夠得到棧的最小元素的 min 函式在該棧中,呼叫 min、push 及 pop 的時間複雜度都是 O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.
提示:
- 各函式的呼叫總次數不超過 20000 次
方法一:輔助棧
解題思路
普通棧的
push()
和pop()
函式的複雜度為 O(1),而獲取棧最小值min()
函式需要遍歷整個棧,複雜度為 O(N)。
本題難點:將
min()
函式複雜度降為 O(1),可通過建立輔助棧實現;- 資料棧 A:棧 A 用於儲存所有元素,保證入棧
push()
函式、出棧pop()
函式、獲取棧頂top()
函式的正常邏輯; - 輔助棧 B:棧 B 中儲存棧 A 中所有 非嚴格降序 的元素,則棧 A 中的最小元素始終對應棧 B 的棧頂元素,即
min()
函式只需返回棧 B 的棧頂元素即可。
- 資料棧 A:棧 A 用於儲存所有元素,保證入棧
因此,只需設法維護好棧 B 的元素,使其保持非嚴格降序,即可實現
min()
函式的 O(1) 複雜度。
函式設計:
push(x) 函式
:重點為保持棧 B 的元素是 非嚴格降序 的。- 將 x 壓入棧 A(即
A.add(x)
); - 若 ① 棧 B 為空 或 ② x 小於等於 棧 B 的棧頂元素,則將 x 壓入棧 B(即
B.add(x)
)。
- 將 x 壓入棧 A(即
pop()
函式:重點為保持棧 A B 的 元素一致性。- 執行棧 A 出棧(即
A.pop()
),將出棧元素記為 y; - 若 y 等於棧 B 的棧頂元素,則執行棧
B
出棧(即B.pop()
)。
- 執行棧 A 出棧(即
top()
函式:直接返回棧 A 的棧頂元素即可,即返回A.peek()
。min()
函式:直接返回棧 B 的棧頂元素即可,即返回B.peek()
。
程式碼
Java 程式碼中,由於 Stack 中儲存的是
int
的包裝類Integer
,因此需要使用equals()
代替==
來比較值是否相等。
class MinStack {
Stack<Integer> A, B;
public MinStack() {
A = new Stack<>();
B = new Stack<>();
}
public void push(int x) {
A.add(x);
if(B.empty() || B.peek() >= x)
B.add(x);
}
public void pop() {
if(A.pop().equals(B.peek()))
B.pop();
}
public int top() {
return A.peek();
}
public int min() {
return B.peek();
}
}
複雜度分析
- 時間複雜度 O(1) :
push()
,pop()
,top()
,min()
四個函式的時間複雜度均為常數級別。 - 空間複雜度 O(N) :當共有 N 個待入棧元素時,輔助棧 B 最差情況下儲存 N 個元素,使用 O(N) 額外空間。
個人理解
- 比較兩個值相等一定要用
equals()
方法,因為 Stack 中存的是 Integer,不能用 == 來判斷相等。 - 元素一致性:上面程式碼中已經有了處理元素一致性的方法,就是在 A 棧中 pop 出來的元素,如果和 B 棧的棧頂元素相等,則將 B 棧的棧頂元素也 pop 出來。我們來看一下為什麼這麼做可以保證元素一致性。
- B 棧是非嚴格遞減的,也就是說,在向 A 棧內新增元素的時候,如果後面的一個元素大於前面一個元素,是不會將元素壓入 B 棧中的。
- 這就避免了我在 A 棧中彈出一個元素,結果在 B 棧中存在,但是不在棧頂,導致最後 B 棧元素不空等各種問題。因為我根本不會將大值壓入 B 棧中。所以只需要比較棧頂元素即可,非嚴格遞減儲存的。
- 為什麼這樣可以,假設壓入 A 棧中第一個元素是最小的,那麼 B 棧只會有一個元素,整個過程中最小元素都是第一個,直到 A 中 pop 出最後一個元素。
方法二:我的解法
我是借鑑了上面的解法,不過我使用的是 Deque
,因為 Stack
已經不推薦使用了。
class MinStack {
Deque<Integer> A,B;
/** initialize your data structure here. */
public MinStack() {
A = new LinkedList<>();
B = new LinkedList<>();
}
public void push(int x) {
A.addFirst(x);
if (B.isEmpty() || x <= B.peekFirst()) {
B.addFirst(x);
}
}
public void pop() {
if (A.removeFirst().equals(B.peekFirst())) {
B.removeFirst();
}
}
public int top() {
return A.peekFirst();
}
public int min() {
return B.peekFirst();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.min();
*/
題解來源
作者:jyd
連結:leetcode-cn.com/problems/bao-han-m...
來源:力扣(LeetCode)
來源:力扣(LeetCode)
連結:leetcode-cn.com/problems/bao-han-m...
本作品採用《CC 協議》,轉載必須註明作者和本文連結