如题:
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终
结果不会超过 231 - 1 。
例如:
输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
这道题在hash专项练习里遇到,最初的方法是循环法(俗称暴力),遍历4个数组,计算每种组合,时间复杂度在O(n^4)。复杂度还蛮大的,应该可以优化,想了半天,没想到啥巧妙的方法。看了其它人的题解,可以优化到O(n^2),思路:遍历AB数组,计算每种组合的和,将和放入到hash桶中,key为和,值为次数。时间复杂度为O(n^2)。接着遍历CD数组,计算各种组合s,查找hash中是否存在-s,找到则累积可能性。时间复杂度为O(n^2)。总的时间复杂度为O(2n^2)。和O(n^4)相比,的确优化了不少。hash需要占空间,空间换时间,不亏。思路倒是很简单,但是的确是没想到,其实就是减少内层循环的次数。遇到同样的题型都可以如此优化。有学会一招。下面是是c语言的解法:
/*
* 解法1:暴力遍历,O(n^4)
* 解法2:使用hash优化暴力算法,O(n^2)
*/
typedef struct hlist {
int nkey, pkey;
int nNum, pNum;
struct hlist *next;
}*hnode;
hnode newHashNode(int key)
{
hnode n = (hnode)calloc(1, sizeof(struct hlist));
if (key < 0){
n->nkey = key;
n->pkey = 0 - key;
n->nNum = 1;
}else{
n->pkey = key;
n->nkey = 0 - key;
n->pNum = 1;
if (key == 0)
n->nNum = 1;
}
return n;
}
int hashKey(int s)
{
if (s < 0)
return (0 - s) % 10000;
else
return s % 10000;
}
int fourSumCount(int* A, int ASize, int* B, int BSize, int* C, int CSize, int* D, int DSize){
int i,j,n = 0,s, key;
hnode hash[10000] = {0}, prev, curr, new;
//特殊情况处理
if (ASize == 0 || BSize == 0 ||CSize == 0 || DSize == 0)
return 0;
//遍历AB和,将其加入到hash桶中,和为key,值为次数
for (i = 0; i < ASize; i++)
{
for (j = 0; j < BSize; j++)
{
s = A[i] + B[j];
key = hashKey(s);
prev = NULL;
curr = hash[key];
while (curr)
{
if (curr->nkey == s)
{
curr->nNum++;
break;
}
else if (curr->pkey == s)
{
curr->pNum++;
break;
}
else
{
prev = curr;
curr = curr->next;
}
}
if (!curr)
{
new = newHashNode(s);
if (prev)
prev->next = new;
else
hash[key] = new;
}
}
}
//遍历CD和s,在hash表中查找-s,统计次数。
for (i = 0; i < CSize; i++)
{
for (j = 0; j < DSize; j++)
{
s = C[i] + D[j];
s = 0 - s;
key = hashKey(s);
curr = hash[key];
while (curr)
{
if (curr->nkey == s){
n += curr->nNum;
break;
}
else if (curr->pkey == s){
n += curr->pNum;
break;
}
else
curr = curr->next;
}
}
}
return n;
}
=============================================================================================
Linux应用程序、内核、驱动开发交流讨论群(745510310),对后端、互联网感兴趣的同学可以加群讨论、交流、资料查找等,前进的道路上,你不是一个人奥^_^。
---------------------
版权声明:本文为CSDN博主「mrsonko」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fuyuande/article/details/99434278