代碼隨想錄算法訓(xùn)練營Day 10 | LeetCode232用棧實現(xiàn)隊列、LeetCode225用隊列實現(xiàn)棧

摘要

  • 用棧實現(xiàn)隊列,用隊列實現(xiàn)棧,雖然可能沒有什么實際應(yīng)用價值,但是對于熟悉棧和隊列的結(jié)構(gòu)以及基本操作是很有意義的。
    • 用兩個棧實現(xiàn)隊列
    • 通過讓隊列循環(huán)來實現(xiàn)棧

今日學(xué)習(xí)的視頻和文章

  • 代碼隨想錄 棧和隊列的基礎(chǔ)
  • C++Primer 棧和隊列部分
  • 數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)C++語言版(第二版)棧和隊列部分

LeetCode232 用隊列實現(xiàn)棧

232. 用棧實現(xiàn)隊列 - 力扣(Leetcode)

  • 今天的題目比較簡單,棧是后進(jìn)先出,而隊列是先進(jìn)先出,用棧實現(xiàn)隊列的關(guān)鍵就在于如何將后進(jìn)先出轉(zhuǎn)化為先進(jìn)先出。
    • 如果我們只用一個棧,能不能做到先進(jìn)先出呢?由于題目要求只能使用棧的標(biāo)準(zhǔn)操作,而彈出先進(jìn)的元素(即棧底的元素)前必須彈出在其之后的所有元素,所以我們應(yīng)該用另一塊內(nèi)存空間來保留這部分元素。而這部分元素的彈出順序是遵循棧的后進(jìn)先出的,由對稱性的想法,這另一個用來保存元素的空間也可以是棧的結(jié)構(gòu)。
    • 例如,這里元素1,2,3入棧,【或】表示棧底
      • 棧in:【1,2,3 ;棧out:【
      • 此時,根據(jù)隊列的先進(jìn)先出,我們要彈出1,將2,3保留在另一個棧中
      • 棧in:【1;棧out:【3,2,
      • 為了代碼邏輯更加簡潔,我們可以統(tǒng)一將棧1的元素都push進(jìn)棧2中,而不是判斷棧1是否還剩余1個元素
      • 棧in:【;棧out:【3,2,1
      • 此時在讓棧2的棧頂元素出棧即可
      • 棧in:【;棧out:【3,2
    • 再插入元素到用棧實現(xiàn)的隊列中的邏輯與元素出隊列的邏輯是對稱的,銜接上面的例子,我們要插入元素4,元素4是后進(jìn)的,所以對于出棧來說它應(yīng)該位于棧底:棧out【4,3,2
      • 棧in:【;棧out:【3,2
      • 此時,將棧out的元素push回棧in中
      • 棧in:【2,3;棧out:【
      • 然后再將元素4 push進(jìn)棧in中
      • 棧in:【2,3,4;棧out:【
      • 這樣就完成了元素4進(jìn)入用棧實現(xiàn)的隊列的操作

完整題解代碼如下

class MyQueue {
private:
    stack<int> in;
    stack<int> out;
public:
    MyQueue() {

    }
    
    void push(int x) {
        while (!out.empty()) {
            in.push(out.top());
            out.pop();
        }
        in.push(x);
    }
    
    int pop() {
        while (!in.empty()) {
            out.push(in.top());
            in.pop();
        }
        int temp = out.top();
        out.pop();// 要注意這里的 pop 會返回值,而C++STL的棧的pop是不返回值的
        return temp;
    }
    
    int peek() {
        while (!in.empty()) {
            out.push(in.top());
            in.pop();
        }
        return out.top();
    }
    
    bool empty() {
        return in.empty() && out.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

LeetCode225 用隊列實現(xiàn)棧

  • 初見題目時的想法:既然用兩個棧能實現(xiàn)隊列,那對稱地來想,是不是能用兩個隊列來實現(xiàn)棧呢?
  • 這里用【表示隊列頭,用】表示隊列尾
    • 假設(shè)元素1,2,3進(jìn)入由隊列實現(xiàn)的棧,那么根據(jù)后進(jìn)先出,此時應(yīng)該彈出的是元素3
    • 隊列1:【1,2,3】;隊列2:【】
    • 如果我們簡單去類比用兩個棧實現(xiàn)隊列,想用兩個隊列實現(xiàn)棧的話
    • 隊列1:【】;隊列2:【1,2,3】
    • 上面的隊列2再pop,還是彈出元素1而不是元素3。
    • 因為隊列是先進(jìn)先出,即使我們模仿棧實現(xiàn)隊列的思路,把要彈出的元素之前的元素保留在另一個隊列中,也無法實現(xiàn)棧。因為在棧的后進(jìn)先出,我們可以通過兩個棧顛倒元素的彈出順序;但是隊列的彈出順序就是我們將元素放入隊列的順序。
  • 然后,我注意到,兩個棧實現(xiàn)隊列中,有一個地方被簡化了邏輯:
    • ”為了代碼邏輯更加簡潔,我們可以統(tǒng)一將棧1的元素都push進(jìn)棧2中,而不是判斷棧1是否還剩余1個元素“
    • 實際上,我們只需要判斷隊列是否出隊到只剩隊尾元素(即最后一個進(jìn)入隊列的元素),然后在按順序保存隊列的其他元素時讓隊尾元素出隊即可。
    • 這樣一來,實際上我們可以只用一個隊列來實現(xiàn)棧,即讓隊首元素出隊后再入隊,直到我們遍歷到原來的隊尾元素,讓其出隊而不再入隊即可。
      • 例子:【1,2,3】-> 【2,3,1】-> 【3,1,2】-> 【1,2】
    • 那么如何push元素到由隊列實現(xiàn)的棧中呢?我們在上面實現(xiàn)的出棧操作中,是固定彈出隊尾元素的,所以我們直接將元素push到隊列中就好了。

完整的題解代碼如下

class MyStack {
private:
    queue<int> q;
public:
    MyStack() {

    }
    
    void push(int x) {
        q.push(x);
    }
    
    int pop() {
        int count = 0;
        while (count < q.size() - 1) {
            q.push(q.front());
            q.pop();
            count++;
        }
        int temp = q.front();
        q.pop();
        return temp;
    }
    
    int top() {
        int temp = pop();
        push(temp);
        return temp;
    }
    
    bool empty() {
        return q.empty();
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容