給定一個數組和滑動窗口的大小,找出所有滑動窗口裏數值的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那麼一共存在6個滑動窗口,他們的最大值分別爲{4,4,6,6,6,5}; 針對數組{2,3,4,2,6,2,5,1}的滑動窗口有以下6個: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
牛客網上劍指offer的題目(書上似乎沒這個題?)
題意很簡單,給你一個長度爲N的數組,對於(0,N-K+1)範圍的每個數,求出i-i+K-1範圍內的最大值。
最開始想到的是RMQ查詢或者線段樹,但感覺這種做法很傻逼,應該不是劍指offer的做法。後來看了下,用單調的雙向隊列即可。就是維護一個雙向的隊列,隊列裏面是有序的,對於當前i,如果從隊列尾部開始查到適合i插入的位置,並把後面的數全部刪除。
代碼如下:
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int> res;
if(size <= 0 || num.size() == 0) return res;
deque<int> d;
for(int i=0;i<num.size();++i){
while(d.size() > 0 && num[d.back()] <= num[i]){
d.pop_back();
}
d.push_back(i);
if(i +1 >= size){
res.push_back(num[d.front()]);
if(d.front() == i+1-size)
d.pop_front();
}
}
return res;
}
};
//這裏在G++下會超時,C++可以通過,應該是G++對STL的優化不太好。
POJ 2823 題目基本相似,不過是要求最大值和最小值,所以需要維護兩個雙端隊列
代碼如下:
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<deque>
#include<cstdio>
using namespace std;
const int MAX = 1e6+10;
int a[MAX],N,K;
deque<int> Max,Min;
int Maxvalue[MAX],Minvalue[MAX];
void solve(){
for(int i=1;i<=N;++i){
while(!Max.empty() && a[Max.back()] < a[i])
Max.pop_back();
Max.push_back(i);
// printf("MaxD = %d\n",Max.v[Max.s]);
while(!Min.empty() && a[Min.back()] > a[i])
Min.pop_back();
Min.push_back(i);
if(i - K +1 > 0){
Maxvalue[i-K+1] = a[Max.front()];
Minvalue[i-K+1] = a[Min.front()];
if(Min.front() == i-K+1)
Min.pop_front();
if(Max.front() == i-K+1)
Max.pop_front();
}
}
for(int i=1;i<=N-K+1;++i){
printf("%d%c",Minvalue[i],i==N-K+1?'\n':' ');
}
for(int i=1;i<=N-K+1;++i){
printf("%d%c",Maxvalue[i],i==N-K+1?'\n':' ');
}
}
//#define test
int main(void){
#ifdef test
freopen("in.txt","r",stdin);
#endif // test
while(scanf("%d%d",&N,&K) != EOF){
for(int i=1;i<=N;++i){
scanf("%d",&a[i]);
}
solve();
}
#ifdef test
fclose(stdin);
#endif // test
return 0;
}
leetcode 239
做法同上,要注意維護的是下標,不是值,如果在雙端隊列插入值的話,無法判斷當前的最大值是否已經超過了這個區間。