数组中是否存在两数之和等于x?

问题

    请给出一个运行时间为nlogn的算法,使之能在给定一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在有两个其和等于x的元素。

    这是算法导论中的一道题目,主要是运行时间为nlogn,如果没有运行时间限制,可以暴力运行n^2就可以得出结论。在这里给出的解决方案运用到了分治法二分查找法

代码

    1.解题思路是先给数组排序,用分治法,运行时间为nlogn。分冶法的思想如下:算法从最高层开始分解,把数组对半分解成更小的数组,直到分解成最小为止,mergeSort代码片段就是这一过程的解释。然后merge方法把左右两边的数据,从最低层开始,逐层开始排序合并,直至最高层,把结果合并,排序结束。

void merge(int* t, int p, int q, int r, int* tmp)
{
	/// 在原始数组上排序,从p开始,到r结束
	int i = p;
	int j = q + 1;
	int k = p;
	while (i <= q && j <= r)
	{
		/// 如果左边小,则用左边的值赋值
		if (t[i] <= t[j])
		{
			tmp[k++] = t[i++];
		}
		/// 否则,用右边的值赋值
		else
		{
			tmp[k++] = t[j++];
		}
	}
	/// 如果左边还有数据,则把左边数据赋给tmp
	while (i <= q)
	{
		tmp[k++] = t[i++];
	}
	/// 如果右边还有数据,则把右边数据赋给tmp
	while (j <= r)
	{
		tmp[k++] = t[j++];
	}
	/// 把tmp赋给t
	for (int z = p; z < k; ++z)
	{
		t[z] = tmp[z];
	}
}

void mergeSort(int* t, int p, int r, int* tmp)
{
	/// 如果左边的开始位置小于右边的结束位置,则递归排序
	if (p < r)
	{
		/// 求出中间长度
		int q = (p + r) / 2;
		/// 左边排序 从p到q
		mergeSort(t, p, q, tmp);
		/// 右边排序 从q+1到r
		mergeSort(t, q + 1, r, tmp);
		/// 合并左边和右边
		merge(t, p, q, r, tmp);
	}
}

    2.然后,一个循环x依次减去数组中的数得到数key,用二分查找法binarySearch去查找在数组中是否存在数key,如果存在,则说明数组中存在两数之和等于x,否则不存在。

int binarySearch(int* t, int l, int r, int key) {
	int p = (l + r) / 2;
	if (p < l || p > r) {
		return -1;
	}
	if (t[p] == key) {
		return p;
	}
	else if (t[p] > key)
	{
		return binarySearch(t, l, p - 1, key);
	}
	else {
		return binarySearch(t, p + 1, r, key);
	}
}

    下面是测试代码用来判断以上代码是否正确,测试数组{ 10, 1, 9, 3, 5, 8, 2, 6, 4, 7 }中是否有2个数之和等于11,返回第一组找到的两个数。

void print(int* t, int length)
{
	for (int i = 0; i < length; ++i)
	{
		printf("%d ", t[i]);
	}
	printf("\n");
}

int main() {
	int a[10] = { 10, 1, 9, 3, 5, 8, 2, 6, 4, 7 };
	int length = sizeof(a) / sizeof(a[0]);
	int tmp[10];
	print(a, length);
	mergeSort(a, 0, length - 1, tmp);
	print(a, length);

	int x = 11;
	for (int i = 0; i < length; ++ i)
	{
		int key = x - a[i];
		int result = binarySearch(a, 0, length, key);
		if (-1 != result && result != i) {
			printf("has tow number [%d] plus [%d] equal to %d.\n", 
				a[i], a[result], x);
			return 0;
		}
	}

	printf("has no tow number plus equal to %d.\n", x);
	return -1;
}
nlogn-result

查找是否存在两数之和等于11的数

总结

    由以上代码可以看出,只要把思路理清,就可以实现此功能代码。来看看运行时间,因为分治法的运行时间是nlogn,而二分查找法的运行时间是logn,但是因为二分查找法在for循环内,所以要乘以n,最终算法复杂度还是nlogn,没有超过nlogn运行时间。
[download id=”1028″ template=”button”]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Z小偉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值