首页 > 代码库 > 求数组中和为给定值的任意两个数
求数组中和为给定值的任意两个数
转载请注明出处:http://blog.csdn.net/ns_code/article/details/24933341
题目:
输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
思路:
最直接的做法是暴力法,两个for循环,时间复杂度为O(n*n),但是这样没有充分利用升序数组这一前提。我们假设数组为A,长度为len,给定的和为sum,最好的方法是先用数组的第一个数A[low]和最后一个数A[high]相加,看是否等于sum,如果等于sum,则找到了一组数,返回true,如果大于sum,则将较大的数向前移动一位,即high--,此时变成了第一个和倒数第二个数相加,如果小于sum,则将较小的数向后移动一位,即low++,此时变成了第二个和最后一个数相加,依此类推,如果low==high时还未找到和为sum的一组数,则返回false。该算法的时间复杂度为O(n),空间复杂度为O(1)。
针对该方法需要给出一些证明,证明如下:
对于一个升序数列A1,A2,...Ak k>=3,如果A1+Ak大于sum,那么考察k-1个数对和A1+Ak,A2+Ak,...Ak-1+Ak有sum<A1+Ak<=A2+Ak<=,...<=Ak-1+Ak,也就是说,Ak与数列中其它任何数的和都不可能等于sum,因此抛弃Ak这个数,对结果没有影响。A1+Ak如果小于sum的话,同理抛弃A1这个数对结果没有影响。
该方法对任意的整数数组都适合。
完整代码
/**************************************************************************************************** 题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。 要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。 例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。 *****************************************************************************************************/ #include<stdio.h> /* 在升序数组A中找出和为sum的任意两个元素,保存在a和b中 */ bool FindTwoNumSum(int *A,int len,int sum,int *a,int *b) { if(A==NULL || len<2) return false; int low = 0; int high = len-1; while(low<high) { if(A[low]+A[high] == sum) { *a = A[low]; *b = A[high]; return true; } else if(A[low]+A[high] < sum) low++; else high--; } return false; } int main() { int A[] = {1,3,7,9,12,15,17,18,19,20}; int len = 10; int sum = 24; int a,b; if(FindTwoNumSum(A,len,sum,&a,&b)) printf("Find two nums,they are:\n%d and %d\n",a,b); else printf("Not find\n"); return 0; }测试结果
/**************************************************************************************************** 题目:输入一个无序的非负整数数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。 要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。 例如输入数组1、7、4、11、6、15和数字15。由于4+11=15,因此输出4和11。 *****************************************************************************************************/ #include<stdio.h> #include<stdlib.h> /* 在无序数组A中找出和为sum的任意两个元素,保存在a和b中 */ bool FindTwoNumSum(int *A,int len,int sum,int *a,int *b) { if(A==NULL || len<2) return false; //各元素均被初始化为false的bool数组 bool *B = (bool*)calloc(sum,sizeof(bool)); if(B == NULL) exit(EXIT_FAILURE); int i; for(i=0;i<len;i++) { if(A[i]>sum) continue; if(B[A[i]] == false) B[sum-A[i]] = true; else { *a = A[i]; *b = sum-A[i]; free(B); B = NULL; return true; } } free(B); B = NULL; return false; } int main() { int A[] = {19,3,9,7,12,20,17,18,1,16}; int len = 10; int sum = 24; int a,b; if(FindTwoNumSum(A,len,sum,&a,&b)) printf("Find two nums,they are:\n%d and %d\n",a,b); else printf("Not find\n"); return 0; }测试结果: