1. 程式人生 > 實用技巧 >薄書的部落格園主題——awescnb

薄書的部落格園主題——awescnb

技術標籤:劍指offer刷題佇列資料結構

劍指 Offer 09. 用兩個棧實現佇列

1、 問題描述

用兩個棧實現一個佇列。佇列的宣告如下,請實現它的兩個函式 appendTail 和 deleteHead ,
分別完成在佇列尾部插入整數和在佇列頭部刪除整數的功能。(若佇列中沒有元素,deleteHead 操作返回 -1 )

示例 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]

提示:
1 <= values <= 10000
最多會對 appendTail、deleteHead 進行 10000 次呼叫

https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/

2、 例項分析

兩個棧stack1 和stack2實現佇列,這道題的意圖是要求我們操作這兩個“先進後出”的棧實現一個“先進先出”的佇列CQueue。
我們通過一個具體的例子來分析往該佇列插入和刪除元素的過程。
首先插入–個元素a,不妨先把它插入到 stack1,此時stack1中的元素有{a},stack2為空。 再壓入兩個元素b和c,還是插入到stack1中,此時stack1中的元素有{a, b,c},其中c位於棧頂,而stack2仍然是空的(如圖(a)所示

)。 這個時候我們試著從佇列中刪除一個元素。按照佇列先入先出的規則,由於a比 b、c先插入到佇列中,最先被刪除的元素應該是a。元素a儲存在stack1中,但並不在棧頂上,因此不能直接進行刪除。注意到stack2我們還一直沒有使用過,現在是讓stack2發揮作用的時候了。如果我們把stack1中的元素逐個彈出並壓入stack2,元素在stack2中的順序正好和原來在stack1中的順序相反。因此經過3次彈出stack1和壓入 stack2操作之後,stack1為空,而stack2中的元素是{c,b,a},這個時候就可以彈出stack2的梭頂a了。此時的stackl為空,而stack2的元素為{c,b},其中b在棧頂(如圖 (b)所示
)。 如果我們還想繼續刪除佇列的頭部應該怎麼辦呢?剩下的兩個元素是b和c, b比c早進入佇列,因此b應該先刪除。而此時b恰好又在棧頂上,因此直接彈出stack2的棧頂即可。這次彈出操作之後,stack1 中仍然為空,而stack2為{c}(如圖 (c)所示)。
從上面的分析中我們可以總結出刪除一個元素的步驟;當stack2中不為空時,在stack2中的棧頂元素是最先進入佇列的元素,可以彈出。如果stack2為空時,我們把stack1中的元素逐個彈出並壓入stack2。由於先進入佇列的元素被壓到stackl 的底端,經過彈出和壓入之後就處於stack2的頂端了,又可以直接彈出。
接下來再插入一個元素d。我們還是把它壓入stack1(如圖(d)所示),這樣會不會有問題呢?我們考慮下一次刪除佇列的頭部stack2不為空,直接彈出它的棧頂元素c (如圖 (e)所示)。而c的確是比d先進入佇列,應該在d之前從佇列中刪除,因此不會出現任何矛盾。
在這裡插入圖片描述

3、 分析總結

定義兩個stack,分別是stack1和stack2,佇列的push和pop是在兩側的,push操作很簡單,只需要在stack1上操作,而pop操作時,先將stack1的所有元素push到stack2中,然後stack2的pop返回的元素即為目標元素,只要stack2不為空下次刪除隊頭元素時可以從Stack2中直接出棧,只有當棧2為空棧1不為空時才將棧1的元素出棧壓入到棧2中。

4、python實現

class CQueue2:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def appendTail(self, value: int) -> None:
        self.stack1.append(value)
    def deleteHead(self) -> int:
        if len(self.stack2)<=0:  # 棧2為空迴圈--只有當棧2為空的時候才將棧1中的元素 壓入棧2中
            while self.stack1:  # 棧1不為空迴圈
                self.stack2.append(self.stack1.pop())  # 棧1中的元素 壓入棧2中  棧1的棧底變成棧2的棧頂
        if not self.stack2:  # 如果棧1棧2都為空 則返回-1
            return -1
        else:
            result = self.stack2.pop()  # 當棧2為不空的時候,棧2的棧頂元素直接出棧
        return result

# Your CQueue object will be instantiated and called as such:
obj = CQueue2()
obj.appendTail(1)
obj.appendTail(2)
obj.appendTail(3)
obj.appendTail(4)
param_2 = obj.deleteHead()
print(param_2)
param_2 = obj.deleteHead()
print(param_2)
param_2 = obj.deleteHead()
print(param_2)
param_2 = obj.deleteHead()
print(param_2)
param_2 = obj.deleteHead()
print(param_2)
obj.appendTail(1)
obj.appendTail(2)
obj.appendTail(3)
obj.appendTail(4)
param_2 = obj.deleteHead()
print(param_2)
param_2 = obj.deleteHead()
print(param_2)