【劍指 Offer】09. 用兩個棧實現隊列

問題描述

用兩個棧實現一個隊列。隊列的聲明如下,請實現它的兩個函數 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)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章