您的位置:首页 > 编程语言

快速寻找满足条件的两个数

2014-04-09 20:23 267 查看

快速寻找满足条件的两个数

提出问题:
能否快速找出一个数组中的两个数字,让这两个数字的和等于一个给定的值,为了简化起见我们假设这个数组中至少存在一组满足要求的解。
例如有如下两个数组,
5,6,1,4,7,9,8 给定sum=10
1,5,6,7,8,9给定sum=10

解法一:

这个题目也不是很难,也很容易理解。但是要得出高效的解法,还是需要一番思考的。

直接的解法是穷举:从数组中任意取出两个数字,计算两者之和是否为给定的数字。

显然其时间复杂度为O(n*n)。这个算法简单,写起来也很容易,但是效率不高。
#include<cstdio>
#include<algorithm>
#define MAX 100005
using namespace std;

int main(int argc,char *argv[])
{
int n,m;
int v[MAX];
int i,j;
int flag=0;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
scanf("%d",&v[i]);
sort(v,v+n);
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(v[i]+v[j]==m)
{
flag=1;
break;
}
}
if(flag)
break;
}
if(flag)
printf("%d %d\n",v[i],v[j]);
else
printf("No Solution\n");

return 0;
}


解法二:

求两个数字的和,我们假设给定的和为sum。一个变通的思路,就是对数组中的每个元素array[i]都判断一下sum-array[i]是否在数组中。这样就变成一个查找的算法了。

在一个无序的数组中查找一个数的时间复杂度为O(n),对于每个数字array[i],都需要查找对应的sum-array[i]在不在数组中,很容易得到时间复杂度还是O(n*n)。这和原始的方法相比并没有改进,但是如果能有高效的查找算法,就能提高整个算法的效率,怎样提高查找效率?

大家很容易就会想到二分查找,这样可以将原来O(n)的查找时间缩短到O(logN)。这样对于每个array[i],都要花费O(logN)去查找对应的sum-array[i]在不在数组中,总的时间复杂度降为O(NlogN),另外将长度为N的数组进行排序本身也需要O(NlogN)的时间,这样总的时间复杂度仍然为O(NlogN)。这样,就改进了原始的算法。

到这里,我们可能会想,先排序在进行二分查找固然可以将时间复杂度从O(n*n)缩短到O(NlogN),但是还有更快的查找方法:Hash表。应为给定一个数字,根据Hash映射查找另外一个数字是否数组中只需要O(1),这样的话,总体的算法复杂度可以降为O(N),但这种方法需要额外的空间进行Hash表的存储。

#include<cstdio>
#include<algorithm>
#define MAX 1005

using namespace std;

int v[MAX];

int main(int argc,char *argv[])
{
int n,m;
int i;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
int temp;
scanf("%d",&temp);
v[temp]++;
}
for(i=1;i<=m;i++)
{
if(v[i]>0)
{
v[i]--;
if(v[m-i]>0)
{
printf("%d %d\n",i,m-i);
break;
}
}
}
if(i>m)
printf("No Solution\n");

return 0;
}
这段代码的前提是知道元素的取值范围是多少,然后用一个数组进行枚举。

解法三:

还可以换个角度思考问题,假设已经给定了这个数组的任意两个元素的和的有序数组,那么利用二分查找,只需要O(NlogN)就可以解决这个问题。当然我们不大可能去计算这个有序数组,应为它需要O(n*n)的时间。但这个方法仍然启发我们可以对两个数字的和进行一个有序遍历。

首先对数组进行排序,时间复杂度为O(NlogN),然后令i=1,j=n-1看array[i]+array[j]是否等于sum,如果是,则结束。如果小于sum,则i=i+1;如果大于sum,则j=j-1。这样只需要在排好的数组上遍历一次,就可以得到最后结果,时间复杂度为O(N)。两部加起来时间复杂度为O(NlogN)。
#include<cstdio>
#include<algorithm>
#define MAX 100005

using namespace std;

int main(int argc,char *argv[])
{
int i,j;
int n,m;
int v[MAX];
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
scanf("%d",&v[i]);
sort(v,v+n);
int low=0;
int high=n-1;
while(low<=high-1)
{
int temp=v[low]+v[high];
if(temp==m)
{
printf("%d %d\n",v[low],v[high]);
break;
}
else if(temp>m)
high--;
else if(temp<m)
low++;
}
if(low>high-1)
printf("No Solution\n");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息