题意:在一个固定长度的滑动窗口里,计算窗口里的最大值,并且这个滑动窗口每次移动一个。
题解:首先想到的是set,窗口滑动,就是删除一个数,增加一个数,都是O(logn)的效率
80ms
class Solution {
public:
multiset<int> m;
vector<int> ans;
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k==0||nums.size()==0)
return ans;
for(int i=0;i<k;i++)
{
m.insert(nums[i]);
}
ans.push_back(*prev(m.end()));
for(int i=k;i<nums.size();i++)
{
multiset<int>::iterator it = m.find(nums[i-k]);
m.erase(it);
m.insert(nums[i]);
ans.push_back(*prev(m.end()));
}
return ans;
}
};
我们还可以用单调栈,实现在窗口滑动的过程中O(1)的效率得到最小值。
单调栈是一个单调递减的栈,入栈,也就是滑动时,如果栈顶元素比它小,则出栈,直到栈顶元素大于等于新元素。与此同时,栈低元素需要判断它的下标是否小于窗口左边,如果小于,栈底也要前进一格。
严格上来说,这也不是栈。
每次滑动窗口时,最大值显然是栈低元素,而进栈的操作,平均是O(1)的效率
60ms
class Solution {
public:
int s1[100005];
int s2[100005];
int bottom1;
int bottom2;
int top1;
int top2;
vector<int> ans;
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k==0||nums.size()==0)
return ans;
for(int i=0;i<k;i++)
{
EnStack(nums[i],i);
}
ans.push_back(s1[bottom1]);
for(int i=k;i<nums.size();i++)
{
EnStack(nums[i],i);
if(s2[bottom2]==i-k)
{
bottom2++;
bottom1++;
}
ans.push_back(s1[bottom1]);
}
return ans;
}
void EnStack(int x,int pos)
{
if(top1==0)
{
s1[top1++]=x;
s2[top2++]=pos;
}
else
{
while(top1!=bottom1&&s1[top1-1]<x)
{
top1--;
top2--;
}
s1[top1++]=x;
s2[top2++]=pos;
}
}
};
看了题解,发现还有更好的方法,就是实现维护两个数组,left数组表示窗口里从左开始的最大值,right数组表示从右开始的最大值。
52ms
class Solution {
public:
int left[100005];
int right[100005];
vector<int> ans;
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k==0||nums.size()==0)
return ans;
for(int i=0,j=nums.size()-1;i<nums.size()&&j>=0;i++,j--)
{
if(i%k==0)
left[i]=nums[i];
else
left[i]=max(nums[i],left[i-1]);
if((j+1)%k==0||j==nums.size()-1)
{
right[j]=nums[j];
}
else
right[j]=max(nums[j],right[j+1]);
}
for(int i=0;i<nums.size()-k+1;i++)
{
ans.push_back(max(right[i],left[i+k-1]));
}
return ans;
}
};