maxSlidingWindow
- 题目链接:
https://leetcode.com/problems/sliding-window-maximum/
- 滑动窗口的题目,比较常见,因为微信蓝桥的文章开始研究,以为比较简单,解答是用的双端数列,我觉得不好,做了一晚上没有成功,今天理一下,还是有点意思,总结一下。2019-4-28
- 入坑链接:
https://mp.weixin.qq.com/s?__biz=MzA4ODIwMDUyNw==&mid=2652995782&idx=1&sn=550c3be98f99466fc34b1a6339a50a35&chksm=8bf8e4e6bc8f6df06a7eaf57b91c69d5f33f202faa10d0b9e9b2d0002efc1e2a9454cd43ff7b&scene=0&xtrack=1&key=06b9089f8b38a19d800023d8397188132b106e6dfff5de26bb6476956221bc9c4b2a1130e1d7093096b76fe8610d3c6a2bac2c13e12eaf884fad188d98e8142b12956c414422c1a5c9b27d10312c91f4&ascene=1&uin=ODQ2NzM1MDM0&devicetype=Windows+10&version=62060739&lang=zh_CN&pass_ticket=EvA%2BVSbpVxTEzKttd%2FcdlRP1OV7q10cfIHPXOWNbW3Ubnoz9nNnVvBWwU8wp3pze
题目要求
Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.
解题要点
主要思路:
- 使用左右指针来模拟窗口,l和r是左右边界。使用m记录窗口中最大值的索引。
- 窗口不断滚动,l和r逐渐增加,当m不在[l, r ]这个区间时,就重新确定m的位置。当窗口拓展,新的元素加入时,需要计较原来窗口的最大值和新加入的元素,使m指向其中较大的一个。记录每一个窗口中的最大值即可。
- 这样的开销在于findMax函数,貌似会耽误很多时间,导致O(n^2)的复杂度。但是findMax和外层的遍历是互补的,findMax的最差情况(最后一个是最大值)会为外层的遍历节省k-1次。反之,倘若原数组是降序排列的,每一次窗口拓展都需要频繁调用findMax,那么findMax很快就可以得到结果,效率不会变差。
实现细节
- 窗口大小和数组进行比较,处理0数组和大窗口的问题。
- 0数组直接返回引用
- 大窗口,在0到n中只找一遍
- 之后初始化,r = k -1,l=0,m=-1,当m在[l, r ]区间时,窗口滑动,如果nums[r] 大于 nums[m],则m=r。当m不在[l, r ]这个区间时,在区间内findMax,返回值为最大值的索引,即为m。
- 保存每次窗口中的最大值nums[m],即可。
答案
答案1
int findMax(vector<int>& nums, int start, int end)
{
int index = start;
for (int i = start; i < end; i++)
{
if (nums[i] > nums[index])
{
index = i;
}
}
return index;
}
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int l = 0, r =0,m=0,index=0;
vector <int> ans;
int n = nums.size();
int * tmp = new int[n + 5];
if (n == 0)
return ans;
if (n <= k)
{
int index = findMax(nums, 0, n);
ans.push_back(nums[index]);
return ans;
}
m = -1;
for (r = k -1,l=0; r < n; r++,l++)
{
if(!(m<=r && m>=l))
m = findMax(nums, l,r+1);
if (nums[r] >= nums[m])
m = r;
tmp[index++] = nums[m];
}
vector <int> ans1(tmp,tmp+index);
return ans1;
}
Runtime: 56 ms, faster than 98.83% of C++ online submissions for Sliding Window Maximum.
Memory Usage: 12.9 MB, less than 92.20% of C++ online submissions for Sliding Window Maximum.
答案2
- 实际上l基本没用,由于向右滚动,可以进行压缩,保证nums[l]是每一个窗口的最大值,每次都读取窗口左边界的值
- 每次窗口拓展的时候,如果超过了k,重新确定l的位置。否则比较nums[r]和nums[l],使得l始终为窗口的最大值索引
#include <cstdio>
#include <vector>
using namespace std;
int findMax(vector<int>& nums, int start, int end)
{
int index = start;
for (int i = start; i < end; i++)
{
if (nums[i] > nums[index])
{
index = i;
}
}
return index;
}
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int l = 0, r = 0;
vector <int> ans;
int n = nums.size();
if (k == 1)
return nums;
if (n == 0)
return ans;
if (n <= k)
{
int index = findMax(nums, 0, n);
ans.push_back(nums[index]);
return ans;
}
l = findMax(nums, 0, k);
ans.push_back(nums[l]);
r = k - 1;
for (int i = k ; i < n; i++)
{
r++;
if (r >= n)
break;
if (r - l == k)
{
l++;
l = findMax(nums, l, r + 1);
}
if (nums[r] >= nums[l])
{
l = r;
}
ans.push_back(nums[l]);
}
return ans;
}
结果
Runtime: 56 ms, faster than 98.83% of C++ online submissions for Sliding Window Maximum.
Memory Usage: 13.1 MB, less than 72.88% of C++ online submissions for Sliding Window Maximum.