劍指offer 59-II 佇列的最大值
阿新 • • 發佈:2020-09-19
題目描述
請定義一個佇列並實現函式 max_value 得到佇列裡的最大值,要求函式max_value、push_back 和 pop_front 的均攤時間複雜度都是O(1)。
若佇列為空,pop_front 和 max_value 需要返回 -1
思路分析
- 對於一個佇列來說,push_back 和 pop_front 的時間複雜度要做到為 O(1) 不難實現
- 現在問題就是如何讓 max_value 這個獲取最大值的操作的時間複雜度為 O(1)。
- 首先我們需要兩個佇列或者一個佇列一個連結串列,一個佇列 deque(雙端佇列) 用來 push_back 和 pop_front,一個連結串列(LinkedList) 用來獲取 max_value
- 每次往佇列新增資料或刪除資料時,直接新增或刪除
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 的大神的解法,如果有更妙的解法,大家多多分享。