239. 滑动窗口最大值 - 力扣(LeetCode)
一、题目要求
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1 输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
二、解法1-暴力破解 O(N^2) 会超时
遍历数组,得到每一次滑动窗口的最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ret;
for(int i = 0;i+k <= nums.size();i++)
{
int max = nums[i];
for(int j = 1;j < k;j++)
{
if(nums[i+j] > max)
max = nums[i+j];
}
ret.push_back(max);
}
return ret;
}
};
三、解法2-更新最大值 O(N) 执行时间长、内存消耗小
用一个 max 保存当前窗口的最大值的下标,然后滑动窗口。
当一个更大或者相等的值到来时,更新max;
当新值小于最大值,但是最大值又失去时,重新计算max;
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ret;
int max = 0; // 滑动窗口当前的最大值的下标
for (int i = 1; i < k; i++) {
if (nums[i] >= nums[max])
max = i;
}
ret.push_back(nums[max]);
for (int i = 0; i + k < nums.size(); i++) {
// 滑动窗口开始滑动
if (nums[i + k] >= nums[max]) // 来了个更大的
{
max = i + k;
} else // 没有来更大的
{
if (i == max) // 最大的没了,重新计算最大的
{
max = i+1;
for (int j = i+1; j <= i+k; j++) {
if (nums[j] >= nums[max])
max = j;
}
}
}
ret.push_back(nums[max]); // 获得最大值
}
return ret;
}
};
四、解法3-优先级队列(大堆)O(N) 执行时间略短,内存消耗高
用优先级队列维护最大值(根),窗口每次移动插入新值,然后把有影响的窗口外的值删除(大于当前窗口最大值,又在窗口外的数)
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ret;
priority_queue<pair<int, int>> q;
for(int i = 0;i < k;i++)
q.emplace(nums[i],i);
ret.push_back(q.top().first);
for(int i = 0;i+k < nums.size();i++)
{
// 窗口开始滑动
q.emplace(nums[i+k],i+k); // 获得新值
while(q.top().second <= i) // 删除在窗口外,但是比窗口的最大值还大的值
{
q.pop(); // 删除根(最大值)
}
ret.push_back(q.top().first);
}
return ret;
}
};
五、解法4-单调队列 O(N) 执行时间短,空间消耗一般
维护一个单调递增队列,窗口移动时,对于将进入窗口的值,如果比目前的队尾的值大,就永久弹出队尾元素,因为将插入的值肯定比队尾的值后离开窗口;
然后排除已经不在窗口的队头的元素,因为维护的是一个单调递增队列,队头肯定是最大的,将队头对应的值插入结果即可;
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
vector<int> ret;
deque<int> q;
for (int i = 0; i < k; i++) {
while (!q.empty()&&nums[i] >= nums[q.back()]) {
q.pop_back();
}
q.push_back(i);
}
ret.push_back(nums[q.front()]);
for (int i = k; i < n; i++) {
while (nums[i] >= nums[q.back()]) {
q.pop_back();
if (q.empty()) {
break;
}
}
q.push_back(i);
while(q.front() <= i-k)
{
q.pop_front();
}
ret.push_back(nums[q.front()]);
}
return ret;
}
};