題目
給定四個包含整數的數組列表 ,計算有多少個元組 ,使得 。
爲了使問題簡單化,所有的 具有相同的長度 N
,且 。
例如:
輸入:
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
函數原型
C
的函數原型:
int fourSumCount(int* A, int ASize, int* B, int BSize, int* C, int CSize, int* D, int DSize){}
邊界判斷
int fourSumCount(int* A, int ASize, int* B, int BSize, int* C, int CSize, int* D, int DSize){
if ( A == NULL || B == NULL || C == NULL || D == NULL )
return 0;
}
算法設計:查找表
第一反應,大概是枚舉了,而枚舉的複雜度是 。
- (625億)
如果使用查找表改進,比如將 D
中的元素放入查找表,D
就不用枚舉直接查找就行。
查找 D
的方法,結合逆向思維,把加法變成減法,製造一個查找數。
A[i] + B[j] + C[k] + D[l] = 0
等式倆邊移位變成:
D[l] = 0 - A[i] - B[j] - C[k]
這樣查找的複雜度是 ,所以枚舉的複雜度是 。
- (1億)
還能不能優化呢?
更抽象一點,其實可以把 的結果放入查找表,只要枚舉一半了,枚舉的複雜度是 。
- (25萬)
int fourSumCount(int* A, int ASize, int* B, int BSize, int* C, int CSize, int* D, int DSize){
if ( A == NULL || B == NULL || C == NULL || D == NULL )
return 0;
int cnt = 0;
int *map = calloc(1<<10, sizeof(int));
// 建立查找表
for(int i=0; i<CSize; i++)
for(int j=0; j<DSize; j++)
map[ C[i] + D[j] ] ++;
for(int i=0; i<ASize; i++)
for(int j=0; j<BSize; j++)
if( map[ 0 - A[i] - B[j] ] )
cnt += map[ 0 - A[i] - B[j] ];
free(map), map = NULL;
return cnt;
}
思路就是這樣,剩下就是解決負下標。
調用 C
語言哈希庫(uthash):
int fourSumCount(int* A, int ASize, int* B, int BSize, int* C, int CSize, int* D, int DSize) {
struct hash {
int value;
int count;
UT_hash_handle hh;
};
struct hash *hashTable = NULL;
int count = 0;
// 將(A[i]+B[j])的每一種可能值放入哈希表中,並記錄其出現次數。
for (int i = 0; i < ASize; i++) {
for (int j = 0; j < BSize; j++) {
int n = -A[i]-B[j];
struct hash *h;
HASH_FIND_INT(hashTable, &n, h);
if (!h) {
h = malloc(sizeof(struct hash));
h->value = n;
h->count = 1;
HASH_ADD_INT(hashTable, value, h);
}
else
h->count++;
}
}
// 在哈希表中查找是否存在(C[i]+D[j])的每一種可能值。
for (int i = 0; i < CSize; i++) {
for (int j = 0; j < DSize; j++) {
int m = C[i]+D[j];
struct hash *h;
HASH_FIND_INT(hashTable, &m, h);
if (h)
count += h->count;
}
}
return count;
}
- 時間複雜度:
- 空間複雜度: