滑动窗口最大值
Leetode我又回来了
题目描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例 :
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
方法1:(超时)
直接比较每个窗口的数,找出最大值,使用STL自带的*max_element()函数
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> out;
int maxnum = 0;
int length = nums.size();
if(length==0) return out;
for(int i = 0 ;i<=length-k;i++)
{
maxnum = *max_element(nums.begin()+i,nums.begin()+i+k);
out.push_back(maxnum);
}
return out;
}
方法2:
使用优先队列priority_queue
,优先队列每次弹出最大值,但是需要一个index判断最大值在原数组中的位置,使用pair<int,int>
,第二个值为index。
时间复杂度:O(nlogn)
空间复杂度:O(n) (指的是队列的空间复杂度)
由于将一个元素放入优先队列的时间复杂度为O(logn),因此总时间复杂度为O(nlogn)。
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> out;
priority_queue<pair<int,int>> window;
int length = nums.size();
if(length==0) return out;
for(int j =0;j<k;j++){
window.push(make_pair(nums[j],j));}
for(int i = 0 ;i<=length-k;i++){
window.emplace(nums[i+k-1],i+k-1);
while(window.top().second<i ){
window.pop();}
out.push_back(window.top().first);
}
return out;
}
方法3:
使用双向队列,队列中存放数组下标。
分为三步:1.比较新加的数与队列尾部指引的数的大小,pop_back队列尾部的小数。push_back新数。
2.判断队首的数是否超出窗口,pop_front过去的数。
3.保存队首的数。
时间复杂度:O(n)
空间复杂度:O(k) (指的是队列的空间复杂度)
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> out;
deque<int> window;
int length = nums.size();
if(length==0) return out;
for(int j =0;j<k;j++){
while(!window.empty() && nums[window.back()]<=nums[j]){
window.pop_back();
}
window.push_back(j);}
for(int i = k-1 ;i<length;i++){
if(window.front() <= i-k ){
window.pop_front();}
while(!window.empty() && nums[window.back()]<=nums[i]){
window.pop_back();}
window.push_back(i);
out.push_back(nums[window.front()]);
}
return out;
}
方法4:
分块
我们可以将数组从左到右按照 k 个一组进行分组,最后一组中元素的数量可能会不足 k 个。
如果 i不是 k 的倍数,用 prefixMax[i] 表示下标 i对应的分组中,以 i 结尾的前缀最大值;suffixMax[i] 表示下标 i对应的分组中,以 i开始的后缀最大值。
时间复杂度:O(n)
空间复杂度:O(n)
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
vector<int> prefixMax(n), suffixMax(n);
for (int i = 0; i < n; ++i) {
if (i % k == 0) {prefixMax[i] = nums[i];}
else {prefixMax[i] = max(prefixMax[i - 1], nums[i]);}
}
for (int i = n - 1; i >= 0; --i) {
if (i == n - 1 || (i + 1) % k == 0) {suffixMax[i] = nums[i];}
else {suffixMax[i] = max(suffixMax[i + 1], nums[i]);}
}
vector<int> ans;
for (int i = 0; i <= n - k; ++i) {
ans.push_back(max(suffixMax[i], prefixMax[i + k - 1]));
}
return ans;
}
效率有点低,花了一个晚上就整了这一道题,也算是全部搞清楚了。