题目来源: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)。未完待续.....