求数组中和为给定值的任意两个数

转载请注明出处: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;
}

    测试结果

我们现在来拓展一下,假设数组是乱序的,而且规定数组中的元素全部为非负整数,同样给定一个数sum,在数组中找出任意两个数,使二者的和为sum。

因为题目中限定了数组中的元素为非负整数,因此我们可以用哈希数组,开辟一个长度为sum的bool数组B[sum],并全部初始化为false,对数组A进行一次遍历,如果当前的元素A[i]大于sum,则直接跳过,否则,继续作如下判断,如果B[A[i]]为false,则将B[sum-A[i]]置为ture,这样当继续向后遍历时,如果有B[A[i]]为true,则有符合条件的两个数,分别为A[i]和sum-A[i]。如果遍历A结束后依然没有发现有B[A[i]]为true的元素,则说明找不到符合条件的元素。

该算法的时间复杂度为O(n),但空间复杂度为O(sum)。或者如果知道非负整数数组A的最大值为MAX,则也可以开辟一个MAX大小的bool数组,思路是一样的。

完整代码如下:

/****************************************************************************************************
题目:输入一个无序的非负整数数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是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;
}

测试结果:

求数组中和为给定值的任意两个数,布布扣,bubuko.com

时间: 2024-10-02 01:29:09

求数组中和为给定值的任意两个数的相关文章

求数组中和为给定值的所有子序列

2017年网易游戏的一道编程题,大致意思是满足组合攻击技能,必须是所选择时技能的和为m(m>0),且所选的这些技能的乘积最大: 分解后主解决两个问题: 其一:求数组中和为m的所有子数组: 其二:在满足一的条件下,求所有子数组的最大值: 主要考察的还是如何求数组中和为m的所有子数组: 如:数组[1,2,3,4,5,6],m=7时,满足条件的子数组有[1,2,4],[3,4],[2,5],[1,6]; 主要使用回溯法解决该问题,思路以后补上: import java.util.ArrayList;

10.排序数组中和为给定值的两个数字

http://zhedahht.blog.163.com/blog/static/2541117420072143251809/ 题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字.要求时间复杂度是O(n).如果有多对数字的和等于输入的数字,输出任意一对即可. 例如输入数组1.2.4.7.11.15和数字15.由于4+11=15,因此输出4和11. 分析:如果我们不考虑时间复杂度,最简单想法的莫过去先在数组中固定一个数字,再依次判断数组中剩下的n

求数组中任意两个数之间所有数字的和

303. Range Sum Query - Immutable   求数组中任意两个数之间所有数字的和 QuestionEditorial Solution My Submissions Total Accepted: 37248 Total Submissions: 146945 Difficulty: Easy Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j),

求任意两个数间的质数个数

输入 数字个数n 最小从4开始,输出n  个升序排列的数字 输出任意两个数之间质数个数的总和 3 4 6 12 out: 6 不知道哪里错了,求解: #include <iostream>#include<string>#include<fstream>#include<math.h> using namespace std;bool yes(int i){ int a=0; for(a=2; a<=sqrt(i); a++) { if(i%a==0)

51.从键盘上输入任意两个数和一个运算符(+、-、*、/),根据输入的运算符对两个数计算,并输出结果

?#include<iostream> using namespace std; int main() { int x,y; char a; cout<<"please input two numbers: "<<endl; cin>>x>>y; cout<<"please input an operational character:"<<endl; cin>>a; s

剑指Offer 面试题40:数组中只出现一次的两个数 题解

面试题40:数组中只出现一次的两个数 提交网址:  http://www.nowcoder.com/practice/e02fdb54d7524710a7d664d082bb7811?tpId=13&tqId=11193 或 http://ac.jobdu.com/problem.php?pid=1351 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 牛客网OJ的输入输出接口是:void Fin

找出升序数组中和为给定值的两个数字

输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字.如果有多对数字的和等于输入的数字,输出任意一对即可. 详细描述: 接口说明 原型: bool FindTwoNumbersWithSum(int aData[], unsignedint uiLength, int sum, int *pNum1, int *pNum2); 输入参数: int aData[]           // 升序数组 unsigned int uiLength // 数组元

[BC]求数组中任意两个数的公约数,,多种情况取最大值

#include <iostream> #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> using namespace std; int main() { int t,i,c,j,n,x,max,k; int a[100005]; scanf("%d",&t); for(j=1;j<=t;j++) {

[LeetCode]1. Two Sum 数组中和为特定值的两个数

Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that