题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
窗口大于数组长度的时候,返回空
示例
输入:[2,3,4,2,6,2,5,1],3
返回值:[4,4,6,6,6,5]
解题思路
方法一:暴力方法
1、思路:依次遍历每个滑动窗口,获取窗口内的最大值。
2、代码:
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int> result;
if (num.size() == 0 || size < 1 || num.size() < size) return result;
int i = 0, j = i + size - 1;
while (j < num.size()) {
int max_val = num[j];
for (int k = i; k < j; k++) {
max_val = max(num[k], max_val);
}
result.push_back(max_val);
i++;
j++;
}
return result;
}
};
3、复杂度:
时间复杂度:O(ns),s为滑动窗口大小;
空间复杂度:O(1)。
方法二:单调队列
1、思路:利用双端队列维护一个单调队列,只需遍历一遍数组:
- 当队列为空时,当前元素入队;
- 当队列不为空时,比较当前元素与队尾元素的大小:若当前元素大于队尾元素,则队尾元素不断地出队,直到当前元素小于队尾元素或队列为空,然后令当前元素入队;
- 当队首元素超出滑动窗口边界时,队首元素出队;
- 当遍历的元素的个数足够形成滑动窗口时,队首元素即为当前滑动窗口的最大值。
以上步骤1、2可以合并为一种情况,为了判断步骤3,可以在队列中保存数组下标。
2、代码:
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int> result;
if (num.size() == 0 || size < 1 || num.size() < size) return result;
deque<int> tmp;
for (int i = 0; i < num.size(); i++) {
while (!tmp.empty() && num[i] > num[tmp.back()]) {
tmp.pop_back();
}
tmp.push_back(i);
if (i - tmp.front() + 1 > size) {
tmp.pop_front();
}
if (i >= size - 1) {
result.push_back(num[tmp.front()]);
}
}
return result;
}
};
3、复杂度:
时间复杂度:O(n);
空间复杂度:O(s)。