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 }
来源:https://www.cnblogs.com/zzw1024/p/11042635.html