PAT.A1044 Shopping in Mars
原创
©著作权归作者所有:来自51CTO博客作者小怪兽会微笑的原创作品,请联系作者获取转载授权,否则将追究法律责任
题意
给出一个数字序列与一个数m,在数字序列中求出所有和值为S的连续子序列(区间下标左端点小的先输出,左端点相同时右端点小的先输出)。若没有这样的序列,求出和值恰好大于S的子序列(即在所有和值大于S的子序列中和值最接近S)。假设序列下标从1开始。
样例(可复制)
16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13
样例输出
提供几个易错的测试数据
注意点
- 本题可以使用二分法和two pointers解决,时间复杂度为O(nlog n)
- lower_bound()函数会返回查找范围内第一个大于等于指定值的数,而之前的upper_bound()函数会返回查找范围内第一个大于指定值的数;也可以不使用这两个自带的函数,自己写个二分查找函数
二分法
#include <bits/stdc++.h>
using namespace std;
int n,m,small=INT_MAX;
int main(){
cin>>n>>m;
int sum[n];//存储一组数中第1个数到第i个数的和
sum[0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&sum[i]);
sum[i]+=sum[i-1];
}
for(int i=1;i<=n;i++){//找到small
int j=lower_bound(sum+i,sum+n,sum[i-1]+m)-sum;
if(sum[j]-sum[i-1]==m){
small=m;break;
}else if(sum[j]-sum[i-1]>m&&sum[j]-sum[i-1]<small)
small=sum[j]-sum[i-1];
}
for(int i=1;i<=n;i++){//输出
int j=lower_bound(sum+i,sum+n,sum[i-1]+m)-sum;
if(sum[j]-sum[i-1]==small)printf("%d-%d\n",i,j);
}
return 0;
}
two pointers
#include <bits/stdc++.h>
using namespace std;
int n,m,small=INT_MAX;
int main(){
cin>>n>>m;
int sum[n];//存储一组数中第1个数到第i个数的和
sum[0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&sum[i]);
sum[i]+=sum[i-1];
}
int j=1;
for(int i=0;i<=n;i++){//找到small
while(j<=n){
if(sum[j]-sum[i]>=m){
if(small>sum[j]-sum[i])small=sum[j]-sum[i];
break;
}
j++;
}
}
j=1;
for(int i=0;i<=n;i++){//输出
while(j<=n){
if(sum[j]-sum[i]>small)break;
if(sum[j]-sum[i]==small){
printf("%d-%d\n",i+1,j);
break;
}
j++;
}
}
return 0;
}