题意
给四个集合,每个集合的元素个数小于4000,其中每个集合中的元素都是整数,让您求在这四个集合中各取一个数使的四个数的和为0.
分析
数据范围 如果用暴力枚举多有的可能性需要1e12的计算量肯定超时。利用中途相遇的思想可以分别枚举两个集合的所有可能性,然后从得到的两个结果集合中找,利用先排序然后二分查找可以达到n^2logn的复杂度。也可以自己实现一个hash表来统计。
二分
二分代码清晰,可以利用库中的函数使代码编写十分方便。容易理解。
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
sum[num++] = A[i] + B[j];
sort(sum, sum + num);
long long cnt = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cnt += upper_bound(sum, sum + num, -C[i]-D[j]) - lower_bound(sum, sum + num, -C[i] - D[j]);
hash实现
先上代码
//在hash表中插入数据, 其中idx全局变量每个测试例赋值1,也可以在hash数组开的足够大且存的数据不会溢出的时候不初始化
void insert(int summ)
{
int temp = summ > 0 ? summ : -summ;
int h = (temp%MAXN + temp / MAXN) % MAXN;
sum[idx] = summ;
pre[idx] = Hash[h];
Hash[h] = idx++;
}
//在查询表中查询数据
int find(int summ)
{
int cnt = 0;
int temp = summ > 0 ? summ : -summ;
int h = (temp%MAXN + temp / MAXN) % MAXN;
int u = Hash[h];
while (u)
{
if(sum[u] == summ)
cnt++;
u = pre[u];
}
return cnt;
}
其中的hash函数是我参考其他人的hash实现,所以就有一个缺点就是如果参数为负数的时候需要转为正数,然后在存的时候存原来的数据;
复杂度分析
二分的复杂度
利用二分的复杂度很容易分析,主要计算在一下代码中
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)//O(n^2)
cnt += upper_bound(sum, sum + num, -C[i]-D[j]) - lower_bound(sum, sum + num, -C[i] - D[j]); //O(logN)
代码中注释处写了复杂度,所以全局复杂度大概是O(n^2logN);其中n是集合中元素的个数,N是sum中元素的个数,无法确定。
利用hash实现的复杂度
当使用hash表来存的时候由于查询的时候可能复杂度略小;
for (int i = 0; i <