1. 程式人生 > 實用技巧 >劍指offer 59-II 佇列的最大值

劍指offer 59-II 佇列的最大值

題目描述

請定義一個佇列並實現函式 max_value 得到佇列裡的最大值,要求函式max_value、push_back 和 pop_front 的均攤時間複雜度都是O(1)。
若佇列為空,pop_front 和 max_value 需要返回 -1

思路分析

  1. 對於一個佇列來說,push_back 和 pop_front 的時間複雜度要做到為 O(1) 不難實現
  2. 現在問題就是如何讓 max_value 這個獲取最大值的操作的時間複雜度為 O(1)。
  3. 首先我們需要兩個佇列或者一個佇列一個連結串列,一個佇列 deque(雙端佇列) 用來 push_back 和 pop_front,一個連結串列(LinkedList) 用來獲取 max_value
  4. 每次往佇列新增資料或刪除資料時,直接新增或刪除
    4.1 在新增時,連結串列從右往左遍歷,如果比當前待插入值小,則將小於待插入值的節點刪除,此時連結串列就是一個有序列表,一旦最大值出連結串列,下一個依然是當前連結串列中的最大值
    4.2 在刪除時,如果佇列中要刪除的值跟當前連結串列中的最大值相等,則將連結串列中的值一同刪除。

java實現

public class MaxQueue {

    Queue<Integer> queue;
    LinkedList<Integer> max;
    public MaxQueue() {
        queue = new LinkedList<>();
        max = new LinkedList<>();//LinkedList是雙端連結串列
    }
    
    public int max_value() {
        return max.size()==0?-1:max.getFirst();
    }
    
    public void push_back(int value) {
        queue.add(value);
        while(max.size()!=0&&max.getLast()<value){
            // 注意:這裡第二個判斷條件不能帶等號,即max中對於當前queue中的具有相同值的元素會全部儲存,
            // 而不是儲存最近的那個。
            max.removeLast();
        }
        max.add(value);
    }
    
    public int pop_front() {
        if(max.size()!=0 && queue.peek().equals(max.getFirst()))
        //Integer型別的值的比較不能直接使用==
            max.removeFirst();
        return queue.size()==0?-1:queue.poll();
    }
}

python實現

import queue
class MaxQueue:
    """1佇列+1雙端佇列"""
    def __init__(self):
        self.queue = queue.Queue() # 佇列
        self.deque = queue.deque() # 雙端佇列

    def max_value(self) -> int:
        if self.deque:
            return self.deque[0]
        else:
            return -1
        # return self.deque[0] if self.deque else -1 或者這樣寫

    def push_back(self, value: int) -> None:
        while self.deque and self.deque[-1] < value:
            self.deque.pop()
        self.deque.append(value)
        self.queue.put(value)
        

    def pop_front(self) -> int:
        if not self.deque: return -1
        ans = self.queue.get()
        if ans == self.deque[0]:
            self.deque.popleft()
        return ans

一開始想到的是用python中函式暴力解,push_back 和 pop_front 可以達到O(1),但是 max_value 最快也只能是 O(nlogn)。
這個想法是看了 LeetCode 的大神的解法,如果有更妙的解法,大家多多分享。