题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
思路
声明一个双端队列deque(代码中indexArray)用来保存有可能是滑动窗口最大值的数字的下标(队列中前面元素一定大于后面元素,队首元素最大):
1.开始时窗口需要占据数组中前size(给定的窗口大小)个元素
如果新的数字大于队列中尾部元素的数值:弹出尾部元素(while循环判断,弹出所有小于新数字的队列中的元素)
如果新的数字小于队列中尾部元素:新数字入队
2.从数组的第size个元素开始向后遍历,思路类似步骤1(每次额外判断队列首元素是否已滑出窗口外),并且每次循环将队列首元素保存至maxInWindow中
代码
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
//声明容器保存滑动窗口最大值
vector<int> maxInWindow;
//判断有效性
if(num.size() >= size && size > 0)
{
//声明双端队列保存疑似滑动窗口最大值的元素的下标
deque<int> indexArray;
//首先覆盖num的前size个位置的元素,才可开始保存最大值
for(unsigned int i = 0 ; i < size ; ++i)
{
//队列若有元素且入队新元素时要弹出所有小于新元素的值(他们不可能为max)
while(!indexArray.empty() && num[i] > num[indexArray.back()])
indexArray.pop_back();
//新元素入队
indexArray.push_back(i);
}
//开始遍历给定数组(保存max并滑动窗口)
for(unsigned int i = size; i < num.size(); ++i)
{
//保存队首元素
maxInWindow.push_back(num[indexArray.front()]);
//判断并入队新元素
while(!indexArray.empty() && num[i] > num[indexArray.back()])
indexArray.pop_back();
//若队首元素已滑出窗口
if(!indexArray.empty() && indexArray.front() <= (int)(i - size))
indexArray.pop_front();
//新元素入队
indexArray.push_back(i);
}
//每次循环先保存队列首元素才入队新元素,故最后一个元素入队后的队首元素未保存
maxInWindow.push_back(num[indexArray.front()]);
}
return maxInWindow;
}
};