問題描述
用兩個棧實現一個隊列。隊列的聲明如下,請實現它的兩個函數 appendTail 和 deleteHead ,分別完成在隊列尾部插入整數和在隊列頭部刪除整數的功能。(若隊列中沒有元素,deleteHead 操作返回 -1 )。
其中:
1 <= values <= 10000
最多會對 appendTail、deleteHead 進行 10000 次調用
示例 1:
輸入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
輸出:[null,null,3,-1]
示例 2:
輸入:
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
輸出:[null,-1,null,null,5,2]
Java 實現
用兩個棧實現一個隊列的功能,即通過兩個先入後出(FILO)實現一個先入先出(FIFO),我們可以用一個棧支持插入操作,另一個棧實現刪除操作。
具體的操作爲:當我們每一次執行插入元素時,直接往第一個棧 stack1 插入元素,根據棧的結構特性,棧底是第一個插入也是下一個待刪除的元素,棧頂是最後插入的元素。當我們想執行刪除操作時,需要將 stack1 的元素依次取出,取到最後才能訪問到該刪除的元素,但同時我們也想保持元素插入的順序,這時就可以用上第二個棧 stack2。假設第一次執行刪除時,stack2位空,則先把 stack1 的元素依次彈出並插入到 stack2 中,直至 stack1完全清空,此時 stack2 的棧頂即爲下一個待刪除的元素,直至棧底依次爲接下來待刪除的元素。此後,每次執行刪除操作只需從 stack2 彈出元素即可。
當 stack2 棧內存在元素的時候,刪除與插入操作分別對 stack2 與 stack1進行操作,且兩個棧之間相互獨立。即刪除操作只在 stack2 進行,插入操作只在 stack1 進行。在 stack2 清空之前,stack1 維持後一批插入的元素及其插入順序。每次當且僅當 stack2 爲空,且需要進行刪除操作時,才從 stack1 向 stack2 轉移數據。如果轉移後 stack2 仍爲空,即此時無元素存在,則返回 -1。
class CQueue {
private Stack<Integer> stack1;
private Stack<Integer> stack2;
public CQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if (!stack2.isEmpty()) {
return stack2.pop();
} else {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
if (stack2.isEmpty()) {
return -1;
} else {
return stack2.pop();
}
}
}
}
複雜度分析
- 空間複雜度:維護兩個棧進行存儲,因此爲 O(n)。
- 時間複雜度:插入操作,明顯爲 O(1)。刪除操作看似爲 O(n),但經過仔細考慮會發現,每次執行刪除時只從 stack2 彈出一次,即便 stack2 爲空,需要從 stack1 將所有元素都轉移一遍,但這個過程同樣被均攤到每一個元素的插入和彈出過程中,因此刪除操作的時間複雜度爲 O(1)。