[编程之美]快速寻找满足条件的两个数

在《编程之美》一书的第2.12个题目描述如下:

能否快速找出一个数组中的两个数字,让这个两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定至少存在一组满足要求的解。

作者给出了3种方案:

[方案一]穷举法:从数组任意取出两个数字,计算两者之和是否为给定的数字。时间复杂度O(N^2),效率较低。

[方案二]将问题变通为一个查找问题:求两个数之和,假定为sum。对于数组中的每个数array[i],判断sum-array[i]是否在数组中。在一个无序数组中查找一个数的复杂度是O(N),对于每个数字都要进行相应的查找,则时间复杂度仍为O(N^2)。为了提高效率,可以相对数组进行排序,然后利用二分查找算法,时间复杂度为O(NlogN)。

[方案三]利用hash表提高查找效率,查找时间为O(1),总的时间复杂度就为O(N)。但是这会使得空间复杂度也为O(N)。

[方案四]先对数组进行排序,然后对数组中的两个数之和进行一个有序的遍历。具体算法:先令i=0,j=n-1,判断array[i]+array[j]是否等于sum,如相等则结束;如小于则i向右移动一个位置,否则j向左移动一个位置。这样时间复杂度为排序O(NlogN)+查找O(N) = O(N(logN+1))

[扩展问题1]:如果将“两个数字”改为“三个数字”或“任意个数字”时,如何求解?

[方案]对于“三个数字”其实就是对于数组中的每个数字array[i]判断数组中的其他数字是否存在两个数字的和为sum-array[i],以此递归下去。

具体算法(C实现):

int index = 0;
bool find(int array[], int n, int start, int m, int sum, int result[]){
	assert(m >= 2);
	if(n-start < m)
		return false;
	int i,j;
	if(m == 2){
		for(i=start,j=n;i<j;){
			if(array[i] + array[j] == sum){
				result[index++] = array[i];
				result[index++] = array[j];
				return true;
			}
			else if(array[i] + array[j] < sum)
				i++;
			else
				j--;
		}
		return false;
	}else{
		for(i=start;i<n;i++){
			result[index++] = array[i];
			if(find(array,n,i+1,m-1,sum - array[i],result)){
				return true;
			}
			index--;
		}
		return false;
	}
	return false;
}

[扩展问题2]:找到最接近的解,算法实现(C语言):

void findNearest(int array[], int n, int sum, int result[]){
	int i,j;
	int minDiff = INT_MAX;
	for(i=0,j=n-1;i<j;){
		if(array[i]+array[j] == sum){
			result[0] = array[i];
			result[1] = array[j];
			return;
		}else{
			int diff = array[i]+array[j] -sum;
			int tmp_i = array[i];
			int tmp_j = array[j];
			if(diff > 0)
				j--;
			else{
				i++;
				diff = -diff;
			}
			if(diff < minDiff){
				minDiff = diff;
				result[0] = tmp_i;
				result[1] = tmp_j;
			}
		}
	}
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值