關於滑動視窗的題目,大概有兩類,一類是“子串”問題;一類是“用單調佇列來解決”的問題
一、“子串問題”
https://labuladong.gitbook.io/algo/di-ling-zhang-bi-du-xi-lie/hua-dong-chuang-kou-ji-qiao-jin-jie
labuladong大佬在這裡總結了滑動視窗這類問題的程式碼框架,很實用。
二、“用單調佇列來解決”的問題
class MaxQueue { queue<int> q; // 佇列 deque<int> d; // 雙端佇列,構造單調佇列 public: MaxQueue() { } int max_value() { if (d.empty()) { return -1; } return d.front(); } void push_back(int value) { while (!d.empty() && d.back() < value) { d.pop_back(); // 插入的同時維護單調佇列 } d.push_back(value); // 加入單調佇列 q.push(value); // 加入佇列 } int pop_front() { if (q.empty()) { return -1; } int ans = q.front(); if (ans == d.front()) { // 判斷移除的佇列中的元素是不是單調佇列的頭部,如果是的話二者都要移除 d.pop_front(); } q.pop(); return ans; // 返回pop出的那個數 } }; /** * 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(); */
class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { vector<int> maxInWindow; // 記錄結果 if (nums.size() >= k && k >= 1) { // 如果陣列的長度大於視窗的大小並且視窗至少長度為1才有意義 deque<int> index; // 建立一個佇列,只把有可能成為視窗中最大值的數值存入 for (int i=0; i<k; i++) { // 未形成視窗 while (!index.empty() && nums[i] >= nums[index.back()]) { // index.pop_back(); // 佇列中遞減排列,因為最大的滑出後,下一個第二大的有可能成為下一個視窗的最大值 } index.push_back(i); // 存下標的目的是知道滑動視窗是否包含一個陣列中的數字 } for (int i=k; i<nums.size(); i++) { // 已經形成視窗 maxInWindow.push_back(nums[index.front()]); // 佇列首部的肯定是最大值 if (!index.empty() && index.front() <= (int)(i-k)) { // 當一個數字的下標與當前處理的數字的下標之差大於或者等於滑動視窗的打小時,這個數字已經從視窗中滑出了 index.pop_front(); // 在頭部刪除 } while (!index.empty() && nums[i] >= nums[index.back()]) { // 將下一個要進來視窗中的數放到合適的位置 index.pop_back(); // 在尾部刪除 } index.push_back(i); } maxInWindow.push_back(nums[index.front()]); // 最後一個視窗的最大值 } return maxInWindow; } };