滑动窗口最大值--单调队列
我們需要一種特別的隊列,這個隊列放進去窗口里的元素,然后隨著窗口的移動,隊列也一進一出,每次移動之后,隊列告訴我們里面的最大值是什么。
每次窗口移動的時候,調用que.pop(滑動窗口中移除元素的數值),que.push(滑動窗口添加元素的數值),然后que.front()就返回我們要的最大值。
然后在分析一下,隊列里的元素一定是要排序的,而且要最大值放在出隊口,要不然怎么知道最大值呢。
但如果把窗口里的元素都放進隊列里,窗口移動的時候,隊列需要彈出元素。
那么已經排序之后的隊列 怎么能把窗口要移除的元素(這個元素可不一定是最大值)彈出呢。
大家此時應該陷入深思…
「其實隊列沒有必要維護窗口里的所有元素,只需要維護有可能成為窗口里最大值的元素就可以了,同時保證隊列里的元素數值是由大到小的。」
那么這個維護元素單調遞減的隊列就叫做「單調隊列,即單調遞減或單調遞增的隊列。C++中沒有直接支持單調隊列,需要我們自己來一個單調隊列」
class Solution { private:class MyQueue { //單調隊列(從大到小)public:deque<int> que; // 使用deque來實現單調隊列// 每次彈出的時候,判斷隊列當前是否為空,并比較當前要彈出的數值是否等于隊列出口元素的數值,如果相等則彈出。void pop(int value) {if (!que.empty() && value == que.front()) {que.pop_front();}}// 如果push的數值大于入口元素的數值,那么就將隊列后端的數值彈出,直到push的數值小于等于隊列入口元素的數值為止。 // 這樣就保持了隊列里的數值是單調從大到小的了。void push(int value) {while (!que.empty() && value > que.back()) {que.pop_back();}que.push_back(value);}// 查詢當前隊列里的最大值int front() {return que.front();}}; public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {MyQueue que;vector<int> result;for (int i = 0; i < k; i++) { // 先將前k的元素放進隊列que.push(nums[i]);}result.push_back(que.front()); // result 記錄前k的元素的最大值for (int i = k; i < nums.size(); i++) {que.pop(nums[i - k]); // 移除滑動窗口最前面元素que.push(nums[i]); //向滑動窗口右側添加元素result.push_back(que.front()); // 記錄對應的最大值}return result;} };在來看一下時間復雜度,使用單調隊列的時間復雜度是 O(n)。
有人可能想了,在隊列中 push元素的過程中,還有pop操作呢,感覺不是純粹的O(n)。
其實,大家可以自己觀察一下單調隊列的實現,nums 中的每個元素最多也就被 push_back 和 pop_back 各一次,沒有任何多余操作,所以整體的復雜度還是 O(n)。
空間復雜度因為我們定義一個輔助隊列,所以是O(k)。
總結
以上是生活随笔為你收集整理的滑动窗口最大值--单调队列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 万能头文件#include<bits/s
- 下一篇: 前K个高频元素(top k)(TX)