leetcode-スタック-キュー-スタック

69078 ワード

LeetCode-スタック-キュー-スタック
文書ディレクトリ
  • LeetCode-スタック-キュー-スタック
  • LeetCode 225-Implement Stack using Queues-キューでスタックを実装-easy
  • LeetCode 232-Implement Queue using Stack-スタックでキューを実現-easy
  • LeetCode 155-Min Stack-最小スタック-easy
  • Leetcode 946-Validate Stack Sequences-検証スタックシーケンス-Medium
  • LeetCode 224 - Basic Calculator - Hard
  • LeetCode 215-Kth Largest Element in an Array-配列のk番目に大きい数-easy
  • 二叉山
  • LeetCode 295-Find Median from Data Stream-中位数を探す-Hard
  • 構想
  • に3種類の要素が追加された場合.
  • コード
  • LeetCode 225-Implement Stack using Queues-キューでスタック-easyを実現
    キューを使用してスタックを実装するには、次の手順に従います.
    push(x) --    x   
    pop() --       
    top() --       
    empty() --        
    

    注意:
    キューの基本的な操作、すなわちpush to back、peek/pop from front、size、is emptyの操作しか使用できません.
    あなたが使っている言語はキューをサポートしていないかもしれません.listまたはdeque(両端キュー)を使用して、標準的なキュー操作であれば、キューをシミュレートできます.
    すべての操作が有効であると仮定できます(たとえば、空のスタックに対してpopまたはtop操作は呼び出されません).
    問題の幹の要求は,キューのback関数,すなわち純粋な一方向キューを使用することはできない.
    では、一時的なキューを借りる必要があります.
    class MyStack {
    public:
        /** Initialize your data structure here. */
        MyStack() {
        }
        
        /** Push element x onto stack. */
        void push(int x) {
    
            //       
            std::queue<int> queTmp;
            queTmp.push(x);
            int nTmp = 0;
    
            while(!queData.empty())
            {
                nTmp = queData.front();
                queTmp.push(nTmp);
                queData.pop();
            }
            
            while(!queTmp.empty())
            {
                nTmp = queTmp.front();
                queData.push(nTmp);
                queTmp.pop();
            }
            //queData.swap(queTmp);
    
        }
        
        /** Removes the element on top of the stack and returns that element. */
        int pop() {
            int nTmp = queData.front();
            queData.pop();
            return nTmp;
        }
        
        /** Get the top element. */
        int top() {
            return queData.front();
        }
        
        /** Returns whether the stack is empty. */
        bool empty() {
            return queData.empty();
        }
    
    private:
        std::queue<int> queData;
    };
    

    なぜかnTmpを使わず、直接push(front())であればメモリ消費がもっと大きい.
    LeetCode 232-Implement Queue using Stack-スタックによるキュー-easyの実装
                :
    
    push(x) --             。
    pop() --          。
    peek() --          。
    empty() --         。
    
    class MyQueue {
    public:
        /** Initialize your data structure here. */
        MyQueue() {
        }
        
        /** Push element x to the back of queue. */
        void push(int x) {
            std::stack<int> sTmp;
            while(!sData.empty())
            {
                sTmp.push(sData.top());
                sData.pop();
            }
            
            sData.push(x);
            
            while(!sTmp.empty())
            {
                sData.push(sTmp.top());
                sTmp.pop();
            }
            //       swap 
            //sTmp.swap(sData);
        }
        
        /** Removes the element from in front of queue and returns that element. */
        int pop() {
            int n = sData.top();
            sData.pop();
            return n;
        }
        
        /** Get the front element. */
        int peek() {
            return sData.top();
        }
        
        /** Returns whether the queue is empty. */
        bool empty() {
            return sData.empty();
        }
    private:
        std::stack<int> sData;
    };
    

    LeetCode 155-Min Stack-最小スタック-easy
    push,pop,top動作をサポートし,定数時間(時間複雑度O(1))内で最小要素を取得できるスタックを設計した.
    push(x) ——     x     。
    pop() ——        。
    top() ——       。
    getMin() ——          。
    

    例:
      :
    ["MinStack","push","push","push","getMin","pop","top","getMin"]
    [[],[-2],[0],[-3],[],[],[],[]]
    
      :
    [null,null,null,null,-3,null,0,-2]
    
      :
    MinStack minStack = new MinStack();
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);
    minStack.getMin();   -->    -3.
    minStack.pop();
    minStack.top();      -->    0.
    minStack.getMin();   -->    -2.
    

    最初の2つの問題の時間的複雑さはいずれもO(n)である.考えは空間で時間を変えることですが、4つだけプライベート変数nMinを追加するとpopの後、
    1つの変数がだめなら、複数の変数を追加します:最小値スタック、topは現在の状態の最小値を記録します.
    コンテナにアクセスするには、空であるかどうかを判断する必要があります.
    class MinStack {
    public:
        /** initialize your data structure here. */
        MinStack() {
        }
        
        void push(int x) {
            sData.push(x);
            if(sMin.empty())
            {
                sMin.push(x);
            }
            else
            {
                sMin.push( x < sMin.top() ? x : sMin.top());
            }
            
        }
        
        void pop() {
            sData.pop();
            sMin.pop();
        }
        
        int top() {
            return sData.top();
        }
        
        int getMin() {
            return sMin.top();
        }
    private:
        std::stack<int> sData;
    
        //     ,top          。
        std::stack<int> sMin;
    };
    

    Leetcode 946-Validate Stack Sequences-検証スタックシーケンス-Medium
    同様にpojプラットフォーム1363 Railsもある.
    pushedとpoppedの2つのシーケンスが与えられ、各シーケンスの値は重複せず、最初の空きスタックで行われたプッシュpushとポップアップpop操作シーケンスの結果である可能性がある場合にのみtrueを返す.そうでなければfalseを返します.
    例1:
      :pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
      :true
      :           :
    push(1), push(2), push(3), push(4), pop() -> 4,
    push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
    

    例2:
      :pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
      :false
      :1     2     。
    

    考え方は、pushedシーケンスをスタックに格納することによって、pushed.top() == poped.front()の判定があり、マッチングはいずれもpopである.最後のスタックが空の場合はtrueを返します.
    この複雑さはO(n)であり,n方ではない.
    class Solution {
    public:
        bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
            stack<int> s;
            int nSize = pushed.size();
            int j = 0;
    
            for (int i = 0; i < nSize; ++i)
            {
                s.push(pushed[i]);
                while(!s.empty() && s.top() == popped[j])
                {
                    s.pop();
                    ++j;
                }
            }
    
            return s.empty() ? true : false;
        }
    };
    

    LeetCode 224 - Basic Calculator - Hard
    単純な文字列式の値を計算するために、基本的な計算機を実装します.
    文字列式には、左かっこ(,右かっこ)、プラス記号+,マイナス記号-,非負の整数およびスペースを含めることができます.
    例:
      : "(1+(4+5+2)-3)+(6+8)"
      : 23
    

    説明:
    与えられた式が有効だと仮定することができます.内蔵のライブラリ関数evalは使用しないでください.
    デジタルスタックとシンボルスタックに基づいて、逆ポーランド式を実現する必要があります.接尾辞式とも呼ばれます.
    設計ステータスマシン:
    '0'-'9'
    parentheses
    '0'-'9'
    '+''-'
    '0'-'9'
    begin
    number state
    operaition state
    フレーム:
    for (int i = 0; i < nLen; ++i)
    {
        if ( s[i] == ' ' ) continue;
    
        switch(state)
        {
            case STATE_BEGIN:
                // judge STATE
                --i
                    break;
            case STATE_NUM:
                // if num, number = ...
                // else, compute, then STATE_OP
                break;
            case STATE_OP:
                // if +-, push, then set bCalc
                // if (, STATE_NUM, unset bCalc
                // if ), compute
                // if num, STATE_NUM
                break;
        } 
    }
    
    if (nRes != 0) 
    {
        stackNum.push(nRes);
        compute(stackNum, stackOp);
    }
    else if( nRes == 0 && stackNum.empty())
    {
        return 0;
    }
    

    完全版:
    class Solution {
    public:
        int calculate(string s) {
            //       (2**31-1   ,   long
            std::stack<long> stackNum;
            std::stack<char> stackOp;
            long nNum = 0;
            enum State state = STATE_BEGIN;
            bool bCalc = false;
            int nLen = s.length();
            for (int i = 0; i < nLen; ++i)
            {
                if (s[i] == ' ') continue;
    
                switch (state)
                {
                case STATE_BEGIN:
                    // judge STATE
                    state = (s[i] >= '0' && s[i] <= '9')
                        ? STATE_NUM
                        : STATE_OP;
                    --i;
                    break;
                case STATE_NUM:
                    // if num, number = ...
                    // else, compute, then STATE_OP
                    if (s[i] >= '0' && s[i] <= '9')
                    {
                        nNum = nNum * 10 + s[i] - '0';
                    }
                    else
                    {
                        stackNum.push(nNum);
                        if (bCalc)
                        {
                            compute(stackNum, stackOp);
                        }
                        nNum = 0;
                        --i;
                        state = STATE_OP;
                    }
                    break;
                case STATE_OP:
                    // if +-, push, then set bCalc
                    // if (, STATE_NUM, unset bCalc
                    // if ), compute
                    // if num, STATE_NUM
                    if (s[i] == '+' || s[i] == '-')
                    {
                        stackOp.push(s[i]);
                        bCalc = true;
                    }
                    else if (s[i] == '(')
                    {
                        state = STATE_NUM;
                        bCalc = false;
                    }
                    else if (s[i] == ')')
                    {
                        compute(stackNum, stackOp);
                    }
                    else if (s[i] >= '0' && s[i] <= '9')
                    {
                        state = STATE_NUM;
                        --i;
                    }
                    break;
                }
            }
    
            if (nNum != 0)
            {
                stackNum.push(nNum);
                compute(stackNum, stackOp);
            }
            else if (nNum == 0 && stackNum.empty())
            {
                return 0;
            }
            return stackNum.top();
        }
    private:
        void compute(std::stack<long> &stackNum, std::stack<char> &stackOp)
        {
            if (stackNum.size() < 2) return;
    
            long nNum1 = stackNum.top();
            stackNum.pop();
            long nNum2 = stackNum.top();
            stackNum.pop();
    
            char cOp = stackOp.top();
            if (cOp == '+')
            {
                stackNum.push(nNum2 + nNum1);
            }
            else if (cOp == '-')
            {
                stackNum.push(nNum2 - nNum1);
            }
            stackOp.pop();
        }
    private:
        enum State {
            STATE_BEGIN = 0,
            STATE_NUM = 1,
            STATE_OP = 2
        };
    
    };
    

    LeetCode 215-Kth Largest Element in an Array-配列でk番目に大きい数-easy
    ソートされていない配列にk番目の最大要素が見つかります.配列ソート後のk番目の最大要素であり、k番目の異なる要素ではないことに注意してください.
    例1:
      : [3,2,1,5,6,4]   k = 2
      : 5
    

    例2:
      : [3,2,3,1,2,4,5,5,6]   k = 4
      : 4
    

    説明:
    kは常に有効であり、1≦k≦配列の長さであると仮定することができます.
    ふたまた山
    最大/小二叉スタック:最大/小値が先に出る完全二叉木.
    最大ヒープ:
    1
    4
    6
    7
    10
    33
    99
    最小ヒープ:
    1
    4
    6
    7
    99
    スタックは優先キューとも呼ばれ、std::priority_queueコンテナに対応しています.
    int main()
    {
        std::vector<int> v({ 6, 10, 1, 7, 99, 4, 33 });
        
        //      
        std::priority_queue<int> big_heap(v.begin(), v.end());
    
        //    
        std::priority_queue<int, std::vector<int>, std::greater<int>> small_heap(v.begin(), v.end());
        
        //    
        std::priority_queue<int, std::vector<int>, std::greater<int>> big_heap_1;
    
        // 99
        std::cout << big_heap.top() << std::endl;
        // 1
        std::cout << small_heap.top() << std::endl;
        
        big_heap.push(1000);
        // 1000
        std::cout << big_heap.top() << std::endl;
        big_heap.pop();
        big_heap.pop();
        big_heap.pop();
    
        // 10
        std::cout << big_heap.top() << std::endl;
    
        return 0;
    }
    


    topをk番目に大きい数にするには、二叉木の残りの要素は、スタックトップのk−1より大きい数、すなわち、1つの要素個数kの最小スタックを借りる必要がある.
    class Solution {
    public:
        int findKthLargest(vector<int>& nums, int k) {
            std::priority_queue<int, std::vector<int>, std::greater<int>> 
                small_heap;
            int nSize = nums.size();
            for(int i = 0; i < nSize; ++i)
            {
                if (small_heap.size() < k)
                {
                    small_heap.push(nums[i]);
                }
                else if ( nums[i] > small_heap.top())
                {
                    small_heap.pop();
                    small_heap.push(nums[i]);
                }
            }
            
            return small_heap.top();
        }
    };
    

    LeetCode 295-Find Median from Data Stream-中位数を探す-Hard
    中位数は、シーケンステーブルの中央にある数です.リスト長が偶数の場合、中央値は中間の2つの数の平均です.
    たとえば、
    [2,3,4]       3
    [2,3]       (2 + 3) / 2 = 2.5
    

    次の2つの操作をサポートするデータ構造を設計します.
    void addNum(int num) -                  。
    double findMedian() -             。
    

    例:
    addNum(1)
    addNum(2)
    findMedian() -> 1.5
    addNum(3) 
    findMedian() -> 2
    

    ステップ:
  • データストリームのすべての整数が0から100の範囲内にある場合、アルゴリズムをどのように最適化しますか?
  • データストリームの99%の整数が0から100の範囲内にある場合、アルゴリズムをどのように最適化しますか?

  • 構想
    最も愚かな方法は、追加するたびに配列をソートし、addNumはO(n)、findMedianはO(1)である.中位数を検索してソートするとaddNumはO(1)、findMedianはO(nlogn)となります.
    両方の操作がランダムであるため,n回の操作の最も理想的な複雑さはn方である.
    考え方は,最上位と最小のスタックでそれぞれ半分のデータを格納し,最上位topを最小のスタックtopより小さく保つことである.
    最小スタックには大きなデータの半分が格納されていることが明らかになった.
    要素を3種類追加した場合.
    2つのスタックsizeが同時に存在する場合:
  • の新しい要素が2つのtopより小さい場合、小さなデータに追加されます(最大スタック).
  • の新しい要素が2つのtopより大きい場合、大きなデータの半分(最小スタック)に追加されます.

  • 最大ヒープは最小ヒープより1つ多い要素:
  • の新しい要素は最も大きなtopより大きく、直接pushは少ない最小のスタックに入る.
  • の新しい要素が最上位のtopより小さい場合は、pushが最大のスタックに入るに違いありませんが、まずtopを最小のスタックに追加します.

  • 最大スタックは最小スタックより1つの要素が少なく、クラスは前の場合よりもよい.
    コード#コード#
    class MedianFinder {
    public:
        /** initialize your data structure here. */
        MedianFinder() {
    
        }
    
        void addNum(int num) {
            if (big_heap.empty())
            {
                big_heap.push(num);
                return;
            }
            int nBigHeap = big_heap.size();
            int nSmallHeap = small_heap.size();
    
            if (nBigHeap == nSmallHeap)
            {
                if (num < big_heap.top())
                {
                    big_heap.push(num);
                }
                else
                {
                    small_heap.push(num);
                }
    
            }
            else if (nBigHeap > nSmallHeap)
            {
                if (num > big_heap.top())
                {
                    small_heap.push(num);
                }
                else
                {
                    small_heap.push(big_heap.top());
                    big_heap.pop();
                    big_heap.push(num);
                }
            }
            else if (nBigHeap < nSmallHeap)
            {
                if (num < small_heap.top())
                {
                    big_heap.push(num);
                }
                else
                {
                    big_heap.push(small_heap.top());
                    small_heap.pop();
                    small_heap.push(num);
                }
            }
    
        }
    
        double findMedian() {
            if (big_heap.size() == small_heap.size())
            {
                return (big_heap.top() + small_heap.top()) / 2.0;
            }
            return (big_heap.size() > small_heap.size())
                ? big_heap.top()
                : small_heap.top();
        }
    private:
        //               
        //      top    top 
        std::priority_queue<int> big_heap;
        std::priority_queue<int, std::vector<int>, std::greater<int>> small_heap;
    
    };