【Aufzeichnung von Fragen】Praxis der Stapelwarteschlange

1. Minimaler Stapel

Themenlink: 155. Minimaler Stack – LeetCode

Fragestamm:

Entwerfen Sie einen Stack, der Push-, Pop- und Top-Operationen unterstützt und das kleinste Element in konstanter Zeit abrufen kann.

Implementieren Sie die MinStack-Klasse:

  • MinStack() Initialisiert ein Stapelobjekt.
  • void push(int val) schiebt das Element val auf den Stack.
  • void pop() Entfernt das oberste Element des Stapels.
  • int top() Ruft das oberste Element des Stacks ab.
  • int getMin() Ruft das kleinste Element im Stack ab.

Beispiel:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"] [[],[-2],[0],[
- 3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

Erklärung:
MinStack minStack = new MinStack();
myStack.push(-2);
myStack.push(0);
myStack.push(-3);
minStack.getMin(); --> gibt -3 zurück.
myStack.pop();
meinStack.top(); --> 内容 0.
minStack.getMin(); --> gibt -2 zurück.

Themenanalyse:

Um den Minimalwert im aktuellen Stack innerhalb der Zeitkomplexität von O(1) zu finden, können wir uns vorstellen, zwei Stacks zu verwenden, ein Stack speichert normalerweise Daten (Datenstack) und der andere Stack speichert den Minimalwert im aktuellen Stack (Mindeststack), damit das Minimum direkt gefunden werden kann.

Jedes Mal, wenn Daten geschoben werden, schiebt die Datenstation normal, und der minimale Stack beurteilt die Größe des minimalen Werts und den aktuellen Wert vor dem Push. Wenn die Push-Daten kleiner als die Oberseite des minimalen Stacks sind, dann schiebt der minimale Stack den aktuellen Wert, andernfalls schiebt es den obersten Wert des Stapels.

Bild-20230426101739729

Wenn die meisten Daten, die in den Stack geschoben werden, größer als der aktuelle Mindestwert sind, erscheinen viele identische und fortlaufende Zahlen im Mindeststack, was eine große Platzverschwendung darstellt.Daher können wir in Betracht ziehen, den Push von zu ändern Mindeststapel Die Regel lautet, dass nur dann, wenn die neu gepushten Daten kleiner als der aktuelle Mindestwert sind, sie in den Mindeststapel gelegt werden , sodass die Daten im Mindeststapel diese Art von Redundanz nicht aufweisen.

[Bildübertragung des externen Links fehlgeschlagen, die Quellseite verfügt möglicherweise über einen Anti-Leeching-Mechanismus, es wird empfohlen, das Bild zu speichern und direkt hochzuladen (img-4feFqUnf-1682496626758)(null)]

Code:

//解法一:
class MinStack {
    
    
public:
    MinStack() {
    
    //这里默认构造函数就不用实现了,因为在这里成员变量会走初始化列表,在初始化列表这里会自动调用成员变量类型的默认构造函数
        
    }    
    void push(int val) {
    
    
        _st.push(val);
        if(_minst.empty() || val <= _minst.top())
        {
    
    
            _minst.push(val);
        }
    }    
    void pop() {
    
    
        if(_st.top() == _minst.top())
        {
    
    
            _minst.pop();
        }
        _st.pop();
    }   
    int top() {
    
    
        return _st.top();
    }
    int getMin() {
    
    
        return _minst.top();
    }
    
    stack<int> _st;
    stack<int> _minst;
};

Bild-20230426100739132

2. Umgekehrte polnische Ausdrücke

Themenlink: 150. Umgekehrte Auswertung polnischer Ausdrücke – LeetCode

Fragestamm:

Sie erhalten ein Array von Zeichenfolgen, tokensdie einen arithmetischen Ausdruck darstellen, der gemäß 逆波兰表示法ausgedrückt wird .

Bitte berechnen Sie diesen Ausdruck. Gibt eine Ganzzahl zurück, die den Wert des Ausdrucks darstellt.

Notiz:

  • Gültige Operatoren sind '+', '-', '*'und '/'.
  • Jeder Operand (Operand) kann eine Ganzzahl oder ein anderer Ausdruck sein.
  • Die Division zwischen zwei ganzen Zahlen schneidet immer gegen Null ab .
  • Der Ausdruck enthält keine Division durch Null.
  • Die Eingabe ist ein arithmetischer Ausdruck, der gemäß der umgekehrten polnischen Notation dargestellt wird.
  • Die Antwort und alle Zwischenergebnisse der Berechnungen können durch 32-Bit- Ganzzahlen dargestellt werden.

Beispiel 1:

Eingabe: tokens = ["2", "1", "+", "3", "*"]
Ausgabe: 9
Erklärung: Diese Formel wird in einen gemeinsamen arithmetischen Infix-Ausdruck umgewandelt: ((2 + 1) * 3) = 9
Beispiel 2:

Eingabe: tokens = ["4", "13", "5", "/", "+"]
Ausgabe: 6
Erklärung: Diese Formel wird in einen gemeinsamen Infix-Rechenausdruck umgewandelt: (4 + (13 / 5 )) = 6
Beispiel 3:

Eingabe: Token = ["10", "6", "9", "3", "+", "-11", " ","/", "", "17", "+", " 5 ", "+"]
Ausgabe: 22
Erklärung: Diese Formel wird in einen gemeinsamen Infix-Rechenausdruck umgewandelt:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ( (10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= ( 0 + 17) + 5
= 17 + 5
= 22

Themenanalyse:

Für die Berechnung des umgekehrten polnischen Ausdrucks traversieren wir, um den ersten Operator zu finden, und nehmen dann die ersten beiden Operanden zur Berechnung heraus. Auf diese Weise können wir uns vorstellen, den Stack zum Speichern von Daten zu verwenden. Wenn der Operator den erreicht Bediener werden zur Bedienung zwei Elemente herausgesprungen

Bild-20230426104416509

Code:

class Solution {
    
    
public:
    int evalRPN(vector<string>& tokens) {
    
    
        stack<int> st;
        for(auto& str : tokens)
        {
    
    
            if(str == "+" || str == "-" || str == "*" || str == "/")//遇到运算符
            {
    
    
                //拿到左右两个操作数
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                switch(str[0])//判断是什么运算,然后将运算结果入栈
                {
    
    
                    case '+':
                        st.push(left + right);
                        break;
                    case '-':
                        st.push(left - right);
                        break;
                    case '*':
                        st.push(left * right);
                        break;
                    case '/':
                        st.push(left / right);
                        break;
                }
            }
            else//遇到数字
            {
    
    
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};

Bild-20230426095455573

Wissen erweitern: Infix-Ausdrücke und Postfix-Ausdrücke

Ein Ausdruck besteht aus Operanden und Operatoren. Die Ausdrücke, die wir im Allgemeinen sehen, setzen den Operator normalerweise zwischen die beiden Operanden. Diese Art von Ausdruck, der den Operator in die Mitte stellt, wird als Infix-Ausdruck bezeichnet. Dieser Ausdruck ist menschenfreundlich, aber nicht so freundlich zu Computern. Der polnische Mathematiker Jan Lukasiewicz schlug eine andere mathematische Darstellung vor, die zwei Darstellungen hat: Der Operator wird vor den Operanden geschrieben , der Polnischer Ausdruck (polnischer Ausdruck) oder Präfixausdruck (Präfixausdruck) genannt wird , wie + AB; Schreiben Sie den Operator nach dem Operanden , genannt Reverse Polish Expression (Umgekehrter polnischer Ausdruck) oder Suffix-Ausdruck (Suffix-Ausdruck), wie z. B. AB+. Der in der obigen Frage erwähnte umgekehrte polnische Ausdruck ist der Postfix-Ausdruck

Hier ist die Idee des Algorithmus, Infix in Suffix umzuwandeln:

  1. Stapel erstellen
  2. Erhalten Sie Infix-Ausdrücke in der Reihenfolge von links nach rechts
    • digitaler Direktausgang
    • Operator
      • Situation 1: Wenn die linke Klammer angetroffen wird, wird sie direkt auf den Stapel geschoben, und wenn die rechte Klammer angetroffen wird, werden alle Operatoren, die nach der linken Klammer im Stapel auf den Stapel geschoben wurden, entfernt und ausgegeben, und die linke Klammer ist aus dem Stack herausgesprungen, aber nicht ausgegeben.
      • Fall 2: Die Multiplikations- und Divisionszeichen werden direkt auf den Stack geschoben, bis ein Operator mit niedrigerer Priorität angetroffen wird, und der Stack wird seinerseits gepoppt.
      • Situation 3: Beim Auftreffen auf ein Pluszeichen und ein Minuszeichen wird der Stapel, wenn er zu diesem Zeitpunkt leer ist, direkt auf den Stapel geschoben, andernfalls werden die Operatoren mit höherer Priorität im Stapel wiederum vom Stapel geholt ( Hinweis: das Pluszeichen und das Minuszeichen gehören zur gleichen Priorität, also wird der Stack auch der Reihe nach gepoppt) bis der Stack leer ist oder die linke Klammer angetroffen wird, stoppen Sie das Popping des Stacks. (Weil die linke Klammer nur erscheint, wenn sie mit der rechten Klammer übereinstimmt).
      • Situation 4: Nachdem die Erfassung abgeschlossen ist, werden die verbleibenden Operationssymbole im Stapel abgelegt und der Reihe nach ausgegeben

3. Stack-Push-and-Pop-Sequenz

Themenlink: Stack-Push- und Pop-Sequenz

Fragestamm:

Geben Sie zwei Integer-Sequenzen ein, die erste Sequenz stellt die Push-Reihenfolge des Stapels dar, bitte beurteilen Sie, ob die zweite Sequenz die Pop-Reihenfolge des Stapels sein kann. Nehmen Sie an, dass alle auf den Stapel geschobenen Zahlen ungleich sind. Beispielsweise ist die Sequenz 1, 2, 3, 4, 5 die Push-Sequenz eines bestimmten Stapels, und die Sequenz 4, 5, 3, 2, 1 ist eine Pop-Sequenz, die der Push-Sequenz entspricht, aber 4, 3, 5, 1, 2 Es kann nicht die Pop-Sequenz der Push-Sequenz sein.

  1. 0<=pushV.length == popV.length <=1000
  2. -1000<=pushV[i]<=1000
  3. Alle Nummern von pushV sind unterschiedlich

Beispiel 1

Eingabe: [1,2,3,4,5],[4,5,3,2,1]

Rückgabewert: wahr

Erläuterung: Sie können push(1)=>push(2)=>push(3)=>push(4)=>pop()=>push(5)=>pop()=>pop()=> übergeben pop () => pop ()
, um die Sequenz [4,5,3,2,1] zu erhalten und wahr zurückzugeben

Beispiel 2

Eingabe: [1,2,3,4,5],[4,3,5,1,2]

Rückgabewert: falsch

Erläuterung: Aufgrund der Push-Reihenfolge von [1,2,3,4,5] und der Pop-Reihenfolge von [4,3,5,1,2] ist es erforderlich, dass 4, 3, 5 vorher eingefügt werden müssen 1, 2 und 1 und 2 können nicht angezeigt werden, aber in einer so dringenden Reihenfolge kann 1 nicht vor 2 angezeigt werden. Wenn es also nicht gebildet werden kann, geben Sie false zurück

Themenanalyse:

Für diese Art von Thema ist die Komplexität in der Tat ein bisschen zu hoch, wenn wir Brute Force erschöpfend wollen, also habe ich jetzt eine Idee, ob wir die Funktionsweise des Stacks simulieren und mit der Popup-Sequenz vergleichen können

Erstellen Sie zuerst einen Stack, durchlaufen Sie dann die Daten in pushV und schieben Sie den Stack und beurteilen Sie dann, ob die Daten oben auf dem Stack gleich den aktuellen Daten in popV sind. Wenn sie gleich sind, öffnen Sie den Stack, andernfalls fahren Sie fort mit push in den Stack, wenn nach dem Durchlaufen von pushV der Stack leer ist, bedeutet das, dass die popV-Sequenz verfügbar ist, true zurückgeben, andernfalls false zurückgeben.

Code:

class Solution {
    
    
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
    
    
        stack<int> st;
        int i = 0;
        for(auto& e : pushV)
        {
    
    
            st.push(e);
            while(!st.empty() && (st.top() == popV[i]))
            {
    
    
                st.pop();
                ++i;
            }
        }
        return st.empty();
    }
};

Bild-20230426105255229

4. Stapel implementiert Warteschlange

Themenlink: 232. Implementieren von Warteschlangen mit Stapeln – LeetCode

Fragestamm:

Bitte verwenden Sie nur zwei Stacks, um eine First-In-First-Out-Warteschlange zu implementieren. Die Warteschlange sollte alle Operationen unterstützen, die von allgemeinen Warteschlangen unterstützt werden (Push, Pop, Peek, Empty):

Implementieren Sie die MyQueue-Klasse:

void push(int x) verschiebt Element x an das Ende der Warteschlange
int pop() entfernt vom Anfang der Warteschlange und gibt das Element zurück
int peek() gibt das Element am Anfang der Warteschlange zurück
boolean empty() gibt true zurück, wenn die Warteschlange ist leer, andernfalls gebe false zurück
Beschreibung:

Sie können nur Standard-Stack-Operationen verwenden – das heißt, nur Push-to-Top-, Peek/Pop-von-Top-, Size- und Is-Leer-Operationen sind zulässig.
Ihre Sprache unterstützt möglicherweise keine Stapel. Sie können list oder deque (Doppelende-Warteschlange) verwenden, um einen Stack zu simulieren, solange es sich um eine Standard-Stack-Operation handelt.

Beispiel 1:

Eingabe:
["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1]
, [2], [], [], []]
Ausgabe:
[null, null, null, 1, 1, falsch]

Beschreibung:
MyQueue myQueue = new MyQueue();
meineWarteschlange.push(1); // Warteschlange ist: [1]
myQueue.push(2); // Warteschlange ist: [1, 2] (ganz links ist vor der Warteschlange)
myQueue.peek(); // gebe 1 zurück
myQueue.pop(); // gebe 1 zurück, Warteschlange ist [2]
myQueue.empty(); // falsch zurückgeben

Themenanalyse:

Entsprechend den Anforderungen des Themas werden zwei Stacks verwendet, um eine Warteschlange zu implementieren. Sowohl der Stapel als auch die Warteschlange sind Containeradapter, aber die bereitgestellten Adapterschnittstellen sind unterschiedlich. Der Stapel ist LIFO und die Warteschlange ist FIFO, also verwenden wir zwei Stapel, um die Warteschlange zu implementieren, und müssen nur die Art des Eintretens und Verlassens steuern Warteschlange.

Hier verwenden wir zwei Stacks, die wir jeweils st_push und st_pop genannt haben.Für die Operation zum Betreten der Warteschlange schieben wir den Wert auf den st_push-Stack.Für die Operation zum Dequeuing geben wir nur die Elemente im st_pop-Stack aus , und dann at Zum richtigen Zeitpunkt werden die Elemente im st_push-Stack auf den st_pop-Stack übertragen. Beachten Sie hier, dass Sie bei jeder Konvertierung alle Elemente im Push-Stack in den Pop-Stack konvertieren müssen, und Sie können nur konvertieren, wenn der Pop-Stack leer ist , da sonst die Datenreihenfolge durcheinander gebracht wird.

Bild-20230426113433998

Code:

class MyQueue {
    
    
public:
    MyQueue() {
    
    //这里默认构造函数就不用实现了,因为在这里成员变量会走初始化列表,在初始化列表这里会自动调用成员变量类型的默认构造函数

    }
    void push(int x) {
    
    
        st_push.push(x);
    }    
    void conversion()//st_push ==> st_pop
    {
    
    
        if(st_pop.empty())
        {
    
    
            while(!st_push.empty())
            {
    
    
                st_pop.push(st_push.top());
                st_push.pop();
            }
        }
    }
    int pop() {
    
    
        conversion();//当pop栈为空时,从push栈中导入所有元素
        int ret = st_pop.top();
        st_pop.pop();
        return ret;
    }    
    int peek() {
    
    
        conversion();
        return st_pop.top();
    }  
    bool empty() {
    
    
        return st_pop.empty() && st_push.empty();
    }
    
    stack<int> st_push;
    stack<int> st_pop;
};

Bild-20230426113936568

5. Warteschlangenimplementierungsstapel

Themenlink: 225. Implementieren eines Stapels mit einer Warteschlange – LeetCode

Fragestamm:

Bitte verwenden Sie nur zwei Warteschlangen, um einen Last-in-First-out (LIFO)-Stack zu implementieren, und unterstützen Sie alle vier Operationen (Push, Top, Pop und Empty) eines normalen Stacks.

Implementieren Sie die MyStack-Klasse:

void push(int x) schiebt das Element x an die Spitze des Stapels.
int pop() entfernt das oberste Element des Stapels und gibt es zurück.
int top() Gibt das oberste Element des Stapels zurück.
boolean empty() Gibt „true“ zurück, wenn der Stack leer ist, ansonsten „false“.

Notiz:

Sie können nur die Grundoperationen der Warteschlange verwenden, dh nach hinten schieben, von vorne sehen/aufspringen, Größe und ist leer.
Ihre Sprache unterstützt möglicherweise keine Warteschlangen. Sie können list (list) oder deque (double-ended queue) verwenden, um eine Warteschlange zu simulieren, solange es sich um eine standardmäßige Warteschlangenoperation handelt.

Beispiel:

Eingabe:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
Ausgabe:
[null, null, null, 2, 2, falsch]

Erklärung:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // gibt 2 zurück
myStack.pop(); // gibt 2 zurück
myStack.empty(); // falsch zurückgeben

Themenanalyse:

Wie bei der vorherigen Frage müssen wir nur die Reihenfolge des Stapelns und Platzierens steuern

Da Sie die Elemente am Ende der Warteschlange erhalten möchten, wenn Sie aus dem Stapel herauskommen möchten, müssen Sie die anderen Elemente in der Warteschlange entfernen, bevor Sie die Elemente am Ende der Warteschlange erhalten können , die Elemente, die aus sind, werden in einer anderen Warteschlange gespeichert, und die Reihenfolge des Eintrags in die Warteschlange ist ebenfalls festgelegt. Ja, die Reihenfolge der Elemente in der Warteschlange bleibt also unverändert, also fügen Sie beim Einfügen von Elementen weiterhin in die nicht leeren ein Warteschlange

Bild-20230426155014066

Code:

class MyStack {
    
    
public:
    queue<int> q1;
    queue<int> q2;
    MyStack() {
    
    //这里默认构造函数就不用实现了,因为在这里成员变量会走初始化列表,在初始化列表这里会自动调用成员变量类型的默认构造函数

    }
    void push(int x) {
    
    //这里在结构上保证必须有一个队列是空的
        if (q1.empty())
            q2.push(x);
        else
            q1.push(x);
    }
    int pop() {
    
    //在需要pop的时候将非空队列的前n个值转换到空队列中,然后pop非空队列
        if (q2.empty())
        {
    
    
            swap(q1, q2);
        }
        //此时q1为空,q2有值
        int size = q2.size();
        for (size_t i = 0; i < size - 1; ++i)
        {
    
    
            q1.push(q2.front());
            q2.pop();
        }
        int ret = q2.front();
        q2.pop();
        return ret;
    }
    int top() {
    
    //非空队列中的最后一个元素即是栈顶元素
        if (q1.empty())
        {
    
    
            return q2.back();
        }
        else
            return q1.back();
    }
    bool empty() {
    
    
        return q1.empty() && q2.empty();
    }
};

Bild-20230426154501554

Acho que você gosta

Origin blog.csdn.net/weixin_63249832/article/details/130388566
Recomendado
Clasificación