-
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组
{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
来解决,该队列中保存的是可能成为最大值的元素的下标。首先遍历所有元素(即窗口滑动),窗口向后滑动的时候,先从队尾把所有比新元素小的元素全部弹出(因为前面的元素肯定比新元素更先滑出,比新元素小的元素显然不可能成为最大值),如果队首元素已经超出窗口范围则将队首元素弹出,然后把新元素下标入队,然后队首元素就是当前窗口的最大值了。遍历的元素数量还没达到窗口大小的时候不能把队首放入结果数组中。结合代码看更容易理解。 -
思路二,也可以每次查找当前窗口中的最大值,但是效率会比较低。可以加入一些条件来减少比较次数,如果新加入的元素比前一个窗口的最大值还大,那么新元素成为最大值,否则如果滑出去的元素不是前一个窗口的最大值的话则最大值不变,否则重新查找最大值。
-
题目给的代码框架中那个
size
参数的unsigned
类型是个大坑,因为unsigned
的数如果运算结果为负数的话就会变成很大的数,代码中涉及到与unsigned
进行运算的地方尽量用加法,如果有减法的话要保证减法结果不会为负数,并且不要让负数或者可能为负数的变量和unsigned
进行比较。
- 思路一,
deque
双端队列。
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int> result;
deque<int> maxQueue;
int length = num.size();
if(size<=0 || length==0) return result;
for(int i=0; i<length; i++){
while(!maxQueue.empty() && num[maxQueue.back()]<=num[i]) maxQueue.pop_back();
// 第二个条件我本来写的是maxQueue.front()<=i-size,但是i-size会为负数
if(!maxQueue.empty() && maxQueue.front()+size<=i) maxQueue.pop_front();
maxQueue.push_back(i);
// 这个条件本来写的是i>=size-1,但是size-1可能为负数
if(i+1 >= size) result.push_back( num[ maxQueue.front() ] );
}
return result;
}
};