windo
题目描述:
给你一个长度为 N 的数组,一个长为 K 的滑动的窗体从最左移至最右端,
你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
Windo position Min value Maxvalue
[ 1 3 -1 ] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7你的任务是找出窗口在各位置时的 max value,min value.
输入格式:
第 1 行n,k,
第 2 行为长度为 n 的数组
输出格式:
2 行,
第 1 行每个位置的 min value,
第 2 行每个位置的 max value
样例输入:
8 3
1 3 -1 -3 5 3 6 7
样例输出:
-1 -3 -3 -3 3 3
3 3 5 5 6 7
数据范围:
20%: n<=500;
50%: n<=100000;
100%: n<=1000000;
k<=n;
时间限制:
三秒(表示程序两秒就能过)
嗯…当我做这道题的时候,lzh学长告诉我这道题是要用单调队列做的…当时还没有学单调队列。然而在于我不信邪,偏要用数组做。//不能多次测试的时候别学我
嗯...偏偏在于我真的试出来了,最开始没有优化的时候过了五组。优化了一下,九组,当时耗时还是3秒,最后的优化终于过而且不到两秒。
嗯...前面废话请自行省略...我只是过来表达一下激动的心情。好了下面上代码:
最初:
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
int nn[1000100],mn[1000100]={},mx[1000100]={};
int main()
{
/*freopen("00.in","r",stdin);
freopen("00.out","w",stdout);*/
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>nn[i];
for(int i=1;i<=n-k+1;i++)
{
int maxx=-10000000,minn=10000000;
for(int j=i;j<i+k;j++)
{
if(nn[j]>maxx)maxx=nn[j];
if(nn[j]<minn)minn=nn[j];
}
mn[i]=minn; mx[i]=maxx;
}
for(int i=1;i<=n-k+1;i++) cout<<mn[i]<<' ';
cout<<endl;
for(int i=1;i<=n-k+1;i++) cout<<mx[i]<<' ';
return 0;
}
第一次优化:
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
int nn[1000100],mn[1000100]={},mx[1000100]={};
int main()
{
/*freopen("00.in","r",stdin);
freopen("00.out","w",stdout);*/
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>nn[i];
int maxx=-10000000,minn=10000000;
for(int i=1;i<=k;i++)
{
if(nn[i]>maxx)maxx=nn[i];
if(nn[i]<minn)minn=nn[i];
}
mn[1]=minn; mx[1]=maxx;
for(int i=2;i<=n-k+1;i++)
{
if((maxx==nn[i-1])||(minn==nn[i-1]))
{
maxx=-10000000,minn=10000000;
if(maxx<nn[i-1+k]) maxx=nn[i-1+k];
if(minn>nn[i-1+k]) minn=nn[i-1+k];
for(int j=i;j<i+k;j++)
{
if(nn[j]>maxx)maxx=nn[j];
if(nn[j]<minn)minn=nn[j];
}
}
else
{
if(maxx<nn[i-1+k]) maxx=nn[i-1+k];
if(minn>nn[i-1+k]) minn=nn[i-1+k];
}
mn[i]=minn; mx[i]=maxx;
}
for(int i=1;i<=n-k+1;i++) cout<<mn[i]<<' ';
cout<<endl;
for(int i=1;i<=n-k+1;i++) cout<<mx[i]<<' ';
return 0;
}
最终优化:
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
int nn[1000100],mn[1000100]={},mx[1000100]={};
int main()
{
/*freopen("00.in","r",stdin);
freopen("00.out","w",stdout);*/
std::ios::sync_with_stdio(false);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>nn[i];
int maxx=-10000000,minn=10000000;
for(int i=1;i<=k;i++)
{
if(nn[i]>maxx)maxx=nn[i];
if(nn[i]<minn)minn=nn[i];
}
mn[1]=minn; mx[1]=maxx;
for(int i=2;i<=n-k+1;i++)
{
if((maxx==nn[i-1])||(minn==nn[i-1]))
{
maxx=-10000000,minn=10000000;
if(maxx<nn[i-1+k]) maxx=nn[i-1+k];
if(minn>nn[i-1+k]) minn=nn[i-1+k];
for(int j=i;j<i+k;j++)
{
if(nn[j]>maxx)maxx=nn[j];
if(nn[j]<minn)minn=nn[j];
}
}
else
{
if(maxx<nn[i-1+k]) maxx=nn[i-1+k];
if(minn>nn[i-1+k]) minn=nn[i-1+k];
}
mn[i]=minn; mx[i]=maxx;
}
for(int i=1;i<=n-k+1;i++) cout<<mn[i]<<' ';
cout<<endl;
for(int i=1;i<=n-k+1;i++) cout<<mx[i]<<' ';
return 0;
}
其实看了会发现第二次与最后一次只差了一点,强烈推荐一个好用的东西:
std::ios::sync_with_stdio(false);
可以去百度一下这是什么。效率特别高,别问我为什么,我也不知道。
好了接下来来说一下我的思路,最初始的,也就是搜索,一次一次搜。
改过之后的也就是先判断每次去掉的是不是最大或最小,不是什么都好说,看新增进来的有没有比最大的大或者比最小的小。没有的话还是在数组里存原来的最大最小。有的话那也就是赋值再存。
但是当去掉的是最大或者最小的时候,再查找一遍(这里应该是可以优化的,但是怪我有点懒)。
最后输出。就这样。