剑指 Offer 59 - I. 滑动窗口的最大值
两种思路
第一:将每一个区间里的降序序列下标存入双端队列,每次存入之后执行一次出队,将坐标不在当前区间里的删除,每一次入队的时候,先将小于当前值的全部出队,然后再入队,循环下来,每一次队首元素即是当前区间的最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n=nums.size();
vector<int>ans;
if(n==0) return ans;
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);
}
ans.push_back(nums[q.front()]);
for(int i=k;i<n;i++){
while(!q.empty()&&nums[i]>nums[q.back()]){
q.pop_back();
}
q.push_back(i);
while(q.front()<=i-k){
q.pop_front();
}
ans.push_back(nums[q.front()]);
}
return ans;
}
};
第二:定义一个最大值,双指针来指向区间首末的下标,当需要删除的元素是最大值时,需要重新计算一下当前最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ans;
int n=nums.size();
if(!n) return ans;
int i=0;
int j=0;
int mmax=INT_MIN;
while(j<n){
mmax=max(mmax,nums[j]);
if(j-i==k){
if(mmax==nums[i]){
mmax=INT_MIN;
for(int l=i+1;l<=j;l++){
mmax=max(mmax,nums[l]);
}
}
i++;
}
if(j-i==k-1){
ans.push_back(mmax);
}
j++;
}
return ans;
}
};
剑指 Offer 59 - II. 队列的最大值
采用双端队列维护最大值,采用队列存储数据
入队时先将双端队列里小于当前值的元素出队,然后存入,这样并不会影响求最大值,因为当前存入的元素一定会在前面所有元素出队之后再出队,所以如果双端队列的长度小于原始队列且双端队列的长度为1时,可以推出双端队列里的第一个元素一定是当前最大值
class MaxQueue {
public:
deque<int>d;
queue<int>q;
MaxQueue() {
}
int max_value() {
if(q.empty()) return -1;
return d.front();
}
void push_back(int value) {
while(!d.empty()&&d.back()<value){
d.pop_back();
}
d.push_back(value);
q.push(value);
}
int pop_front() {
if(q.empty()) return -1;
int m=q.front();
if(m==d.front()) d.pop_front();
q.pop();
return m;
}
};