左神算法进阶班2_7滑动窗口

Problem:
  生成窗口最大值数组
  【题目】
    有一个整型数组arr和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。
    例如,数组为[4, 3, 5, 4, 3, 3, 6, 7],窗口大小为3时:
    [4 3 5] 4 3 3 6 7 窗口中最大值为5
    4[3 5 4] 3 3 6 7 窗口中最大值为5
    4 3[5 4 3] 3 6 7 窗口中最大值为5
    4 3 5[4 3 3] 6 7 窗口中最大值为4
    4 3 5 4[3 3 6] 7 窗口中最大值为6
    4 3 5 4 3[3 6 7] 窗口中最大值为7
    如果数组长度为n,窗口大小为w,则一共产生n - w + 1个窗口的最大值。
    请实现一个函数。
    输入:整型数组arr,窗口大小为w。
    输出:一个长度为n - w + 1的数组res,res[i]表示每一种窗口状态下的最大值。
    以本题为例,结果应该返回{ 5,5,5,4,6,7 }。

Solution:
  使用左右指针L, R,
  R移一步,一个数进入窗口,L向右移动一步,一个数出窗口
  L, R只能向右移动,且R > L

  【求一个窗口的实时最大值】
    使用双向链表,或双向队进行存储
   R移动:
    保证对列中从左向右维持为从大到小的排序,那么头数永远为最大
    每进一个数从尾部压入,一旦发现新的数比队列的末尾数大,即一旦压入进去,
    则打破了从大到小的顺序,故需要将队列末尾的数弹出,压入的新数比队列末尾的数小,则入栈,否则一直从末尾弹出。
    切记,每次从尾部压入的数都必须记住其在原数组中的下标值。
    故双向队列中存数据在数组中的下标值就行,不用真的存实际的值,因为可以根据下角标找值。
   L移动:
    每一次L,就验证出窗口的数是不是队列的头,即队列头的数的下角标是不是原数组的下角标,是的话从头部弹出,否则L继续移

Code:

 1 #pragma once
 2 #include <iostream>
 3 #include <deque>
 4 #include <vector>
 5 
 6 using namespace std;
 7 
 8 
 9 vector<int> getWindowsMax(const vector<int>num, const int w)
10 {
11     if (w > num.size())
12         return { -1 };
13     vector<int>res;
14     deque<int>index;
15     for (int l = 0, r = 0; r < num.size(); ++r)
16     {
17         if (r - l >= w)//窗口移动,
18         {
19             if (index[0] == l)//若对头数为窗口左边界数,则弹出
20                 index.pop_front();
21             ++l;//右移
22         }
23         while (!index.empty() && num[r] >= num[index.back()])//若将压入的数比队尾的数大,则弹出
24             index.pop_back();
25         index.push_back(r);// 压入队尾
26 
27         if (r - l == w - 1)//为窗口大小
28             res.push_back(num[index.front()]);
29     }
30     return res;
31 }
32 
33 void Test()
34 {
35     vector<int>v;
36     v = { 4,3,5,4,3,3,6,7 };
37     v = getWindowsMax(v, 3);
38     for (auto a : v)
39         cout << a << "  ";
40     cout << endl;
41 }

猜你喜欢

转载自www.cnblogs.com/zzw1024/p/11042635.html