算法与数据结构实验题 1.3 寻找幸运值
★ 实验任务
给出两个已按升序排列的数组 a[1..n],b[1..m],如果存在 i,j,使得a[i]+b[j]==k,我们便说已找到幸运值。请你判断能不能找到幸运值。
★数据输入
输入第一行为正整数 n,m,k。(1<=k<=10^9)
第二行为 n 个正整数 a[1..n]。(1<=ai<=10^9)
第三行为 m 个正整数 b[1..m]。(1<=bi<=10^9)
80%的数据 1<=n,m<=1000.
100%的数据 1<=n,m<=100000.
★数据输出
如果能找到幸运值,输出 yes。否则输出 no。
输入示例
3 3 8
1 2 3
4 6 7
输出示例
yes
输入示例
3 3 4
1 2 3
4 6 7
输出示例
no
思路:
若是暴力枚举,则时间复杂度为O(n^2),对于20%的数据会超时。
改进:
k已知,对于a数组中的任意一个数,是否在b数组中存在k-a[i]?可以使用二分查找,时间复杂度降为O(nlnm)。
如果再优化,可以考虑n和m的大小,采取O(nlgm)或者O(mlgn)的算法。
附上代码
#include<iostream>
using namespace std;
int a[100001],b[100001];
int found(int x,int y,int k) //二分查找
{
int mid=x+(y-x)/2;
if(x>y) //查找完毕没有找到答案,返回0
return 0;
else
{
if(b[mid]==k)
return 1; //找到!返回1
else if(b[mid]>k)
return found(x,mid-1,k); //找左边
else
return found(mid+1,y,k); //找右边
}
}
int main()
{
int n,m,k,i,j;
int flag=0;
cin>>n>>m>>k;
for(i=0;i<n;i++)
{
cin>>a[i];
}
for(i=0;i<m;i++)
{
cin>>b[i];
}
for(i=0;i<n;i++)
{
if(k-a[i]<=b[m-1]) //当b数组中有可能存在答案时,调用二分查找
{
if(found(0,m-1,k-a[i]))
{
flag=1;
break;
}
}
}
if(flag) cout<<"yes"<<endl;
else cout<<"no"<<endl;
return 0;
}
经ACM大佬指点,对代码进行了进一步改进。
巧妙利用这两个数组递增的特性,仅需存入a数组,用变量cura存a数组的下标,定义cura初始值为n-1,将a数组倒序与数组b中的数字进行求和,若a[cura]+b大于k,则cura自减,继续读入数组b,继续求和判断,如此循环。若a[cura]+b=k,则跳出循环,输出yes;若当cura=0时a[cura]+b仍不等于k,则跳出循环,输出no。
时间复杂度降为O(n),空间复杂度也一并降低。
附上代码
#include<cstdio>
#include<iostream>
using namespace std;
int a[100001], b;
int main()
{
int n,m,k,i,j,cura;
int flag=0;
cin>>n>>m>>k; cura = n - 1;
for(i=0;i<n;i++) scanf("%d", &a[i]); //相较于C++的cin输入流,C语言的输入函数scanf能节省大量时间
for(i=0;i<m;i++)
{
scanf("%d", &b);
while (cura >= 0 && a[cura] + b > k) cura--;
if (cura < 0) break;
else if (a[cura] + b == k)
{
cout<<"yes"<<endl; return 0;
}
}
cout<<"no"<<endl;
return 0;
}
感受到了大佬的力量233