1. 程式人生 > >[LeetCode] 面試題59 - II. 佇列的最大值

[LeetCode] 面試題59 - II. 佇列的最大值

題目:


分析:

本題要求三個方法的時間複雜度都是O(1),對於push_back和pop_front都是好實現的

但是對於max_value,正常情況下要進行遍歷才能獲得最大值,那麼如何才能在O(1)的時間複雜度下獲得最大值?

O(1)時間複雜度意味著直接便可以獲得最大值,一開始的想法是設定兩個變數,一個最大值max,一個第二大值max_2,每次push_back時進行更新,若pop_front的值與最大值相同,便讓max = max_2

但這樣有個問題,當連續兩次pop_front,同時前兩大的數字都被pop出去時,max與max_2儲存的值都是錯誤的,如果要重新確定max與max_2的值,又要進行遍歷了

後來看了題解,裡面提到維護一個排序佇列(雙向),當一個元素cur插入時,它前面所有比它小的值都不會對最大值有影響,而比它大的已經出隊了,因為正常出隊時,出到cur時,它前面的所有值已全部出隊,所以插入時更新雙向排序佇列,只保留比當前值大的值的有序佇列,便可以直接取到max_value,同時不必擔心連續出隊導致的找不大最大值,如果出隊的值真好是當前的最大值,只需要將雙向佇列的隊頭出隊即可

至於為何時間複雜度為O(1), 題解中提到:

我的理解是,在插入時,會將小於當前值的值出隊,不過這個出隊的操作次數是有限的,一個插入操作最多隻有n個出隊操作,更多的情況是小於n個操作,也就是說n個插入操作總共進行了n次出隊,平均下來就是O(1)的複雜度

程式碼:

class MaxQueue {
    queue<int> que;
    deque<int> deq;
public:
    MaxQueue() {

    }
    
    int max_value() {
        if(deq.empty()) return -1;
        return deq.front();

    }
    
    void push_back(int value) {
        while(!deq.empty() && deq.back()<value)
            deq.pop_back();
        deq.push_back(value);
        que.push(value);
    }
    
    int pop_front() {
        if(que.empty()) return -1;
        int res = que.front();
        que.pop();
        if(res == deq.front())  deq.pop_front();
        return res;
    }
};

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue* obj = new MaxQueue();
 * int param_1 = obj->max_value();
 * obj->push_back(value);
 * int param_3 = obj->pop_front();
 */

&n