POJ2785——4 Values whose Sum is 0(二分查找的应用)

题目来源:http://poj.org/problem?id=2785

题目大意:给定长度相等的四列数,要求从每列中选择一个数,求出4个数加和为0的所有组合。

解题思路:如果选用暴力的方法,时间复杂度为O(n^4),最终肯定会超时。为了降低时间复杂度可以选用二分法,先将前两列数的所有组合结果求出存放在一个数组中,再进行排序,然后利用二分查找去有序的数组中查找后两列组合结果的相反数。该方法的时间复杂度为O(n*nlongn)。

第一种实现方式代码如下:

/*
* Copyright: (c) 2019
*
* 文件名称:  ACM2785.cpp	
* 文件标识:
* 摘	要:
*
* 版	本: 1.0
* 作	者: RF_LYF
* 创建日期:	 2019/5/16  8:00
*/
#include <stdio.h>
#include <algorithm>
int A[4001];
int B[4001];
int C[4001];
int D[4001];
int sum1[16000001];
int sum2[16000001];
int ans ,r;
void find(int value)
{
	int low = 0, high = r - 1;
	int mid = 0;
	while(low < high)//保证找到第一个与传入值相等的位置
	{
		mid = low + (high - low) / 2;
		if(sum1[mid] < value)
			low = mid + 1;
		else
			high = mid;
	}
	while(sum1[low] == value && low < r)
	{
		ans++;
		low++;
	}
}
int main()
{
	int row;
	while(~scanf("%d", &row))
	{
		for(int i = 0; i < row; ++i)//n
		{
			scanf("%d%d%d%d", &A[i], &B[i], &C[i], &D[i]);
		}
		r = 0;
		for(int i = 0; i < row; ++i)//n^2
		{
			for(int j = 0; j < row; ++j)
			{
				sum1[r++] = A[i] + B[j];
				sum2[r - 1] = C[i] + D[j];
			}
		}
		ans = 0;
		std::sort(sum1, sum1 + r);//nlogn
		for(int i = 0; i < r; ++i)//n * nlogn
		{
			find(-sum2[i]);
		}
		printf("%d\n", ans);
	}
	return 0;
}

第二种实现方式代码如下:

/*
* Copyright: (c) 2019
*
* 文件名称:  ACM2785_2.cpp	
* 文件标识:
* 摘	要:
*
* 版	本: 1.0
* 作	者: RF_LYF
* 创建日期:	 2019/5/17  10:24
*/
#include <stdio.h>
#include <algorithm>
int A[4001];
int B[4001];
int C[4001];
int D[4001];
int sum1[16000001];
int sum2[16000001];


//lower_bound(begin,end,num)找到第一个大于或者等于num的数字,找到后返回该数字的地址,不存在返回end
//upper_bound(begin,end,num)找到第一个大于num的数字,找到返回该数字的地址,不存在则返回end
//lower_bound和upper_bound都是利用二分查找的方法在一个排好的数组进行查找
int main()
{
	int row;
	while(~scanf("%d", &row))
	{
		for(int i = 0; i < row; ++i)//n
		{
			scanf("%d%d%d%d", &A[i], &B[i], &C[i], &D[i]);
		}
		int r = 0;
		for(int i = 0; i < row; ++i)//n^2
		{
			for(int j = 0; j < row; ++j)
			{
				sum1[r++] = A[i] + B[j];
				sum2[r - 1] = C[i] + D[j];
			}
		}
		int ans = 0;
		std::sort(sum1, sum1 + r);//nlogn
		for(int i = 0; i < r; ++i)//n * nlogn
		{
			ans += std::upper_bound(sum1, sum1 + r, -sum2[i]) - std::lower_bound(sum1, sum1 + r, -sum2[i]);
		}
		printf("%d\n", ans);
	}
	return 0;
}

但是以上两种实现方式,虽然能够解决该题目,但是使用内存方面和计算速度方面都比较差。因此想利用散列表的方式来解决这一问题,如果能巧妙的解决散列冲突的问题,那么在查找数据方面时间复杂度会降低到O(1)。未完待续.....

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值