[454].四數相加 II

 


題目

給定四個包含整數的數組列表 A,B,C,DA , B , C , D ,計算有多少個元組 (i,j,k,l)(i, j, k, l),使得 A[i]+B[j]+C[k]+D[l]=0A[i] + B[j] + C[k] + D[l] = 0

爲了使問題簡單化,所有的 A,B,C,DA, B, C, D 具有相同的長度 N,且 0N5000 ≤ N ≤ 500

例如:

輸入:
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;
}

 


算法設計:查找表

第一反應,大概是枚舉了,而枚舉的複雜度是 Θ(n4)\Theta(n^{4})

  • 5004=625,0000,0000500^4 = 625, 0000, 0000(625億)

如果使用查找表改進,比如將 D 中的元素放入查找表,D 就不用枚舉直接查找就行。

查找 D 的方法,結合逆向思維,把加法變成減法,製造一個查找數。

  • A[i] + B[j] + C[k] + D[l] = 0

等式倆邊移位變成:

  • D[l] = 0 - A[i] - B[j] - C[k]

這樣查找的複雜度是 Θ(1)\Theta(1),所以枚舉的複雜度是 Θ(n3)\Theta(n^{3})

  • 5003=1,2500,0000500^3 = 1, 2500, 0000(1億)

還能不能優化呢?

更抽象一點,其實可以把 C[k]+D[l]C[k]+D[l] 的結果放入查找表,只要枚舉一半了,枚舉的複雜度是 Θ(n2)\Theta(n^{2})

  • 5002=25,0000500^2 = 25, 0000(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;
}
  • 時間複雜度:Θ(n2)\Theta(n^{2})
  • 空間複雜度:Θ(n2)\Theta(n^{2})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章