1. 程式人生 > >找出陣列中符合條件的數對的個數

找出陣列中符合條件的數對的個數

題目:一個整型陣列,元素取值可能是1~N(N是一個較大的正整數)中的任意一個數,相同數值不會重複出現。設計一個演算法,找出數列中符合條件的數對的個數,滿足數對中兩數的和等於N+1。
方法一:排序+二分查詢。先對陣列進行排序,然後遍歷該有序陣列,同時使用二分查詢方法,查詢對應的值是否存在(例如,有序陣列中某元素值為a,那麼在該有序陣列中,使用二分查詢方法,來查詢(N+1- a)是否存在)。

方法二:排序+線性掃描。先對陣列進行排序,然後使用兩個指示器(front和back)分別指向第一個和最後一個元素,再從兩端同時向中間遍歷,直到兩個指標交叉。
(1)如果A[front] + A[back] > N+1,則back - -。
(2)如果A[front] + A[back] = N+1,則計數器加1,back - -,同時front++。
(3)如果A[front] + A[back] < N+1,則front++。
重複上述步驟,O(n)時間就可以找到所有數對,因此總體複雜度為O(nlogn)。
通過給出一個有序陣列,來觀察方法二的實現,如下:

#include <iostream>

void FindSum(int arr[], int len, int sum)
{
    int i,j;
    for (i = 0, j = len - 1; i < len && j >= 0 && i < j;)
    {
        if (arr[i] + arr[j] < sum)
            i++;
        else if (arr[i] + arr[j] == sum)
        {
            printf("%d + %d = %d\n"
, arr[i], arr[j], sum); i++; j--; } else j--; } } int main(int argc, const char * argv[]) { int arr[] = {1,2,3,4,5,6}; int len = sizeof(arr)/sizeof(int); FindSum(arr, len, 8); return 0; }

方法三:hash法。即使用hash法,對陣列進行計數排序,將1~N個數放在一塊很大的空間裡面,比如1放在1號位,N放在n號位置,然後對每個數m,在hash表中尋找“下標N+1- m 對應的值是否存在“,若存在,則構成一對滿足要求的數對。總體時間複雜度為O(n)。

拓展一:
如果是任意陣列,而不是本題的有規律陣列,如何求解陣列對?即給定一個任意整數陣列array[n],尋找陣列中和值為SUM的數對。(方法同上)
方法一:排序+二分查詢。先對陣列進行排序,然後遍歷該有序陣列,同時使用二分查詢方法,查詢對應的值是否存在(例如,有序陣列中某元素值為m,那麼在該有序陣列中,使用二分查詢方法,來查詢(SUM - m)是否存在)。

方法二:排序+線性掃描。先將陣列排序後(一般最快的排序演算法時間複雜度為O(nlogn)),然後設兩個指標指向陣列的兩端,判斷這兩個指標對應元素之和是否為SUM,如果等於SUM,則找到了,繼續查詢;如果小於SUM,那麼首指標遞增;如果大於SUM,尾指標遞減,直到兩個指標相遇時,如果還是沒有和為SUM的元素對出現,那麼返回false。

方法三:hash法。將陣列儲存到hash表中,對每個數m,在hash表中尋找SUM - m,此時時間複雜度為 O(n)。需要注意的是,如果陣列空間很大,超過了記憶體的容量,那麼可以按照hash(max(m, SUM - m))%g,將資料分到g個小的組中,然後對每個小組進行單獨處理,此時時間複雜度還是O(n)。

拓展二:
已知大小分別為 m、n 的兩個無序陣列 A、B 和一個常數 c,求滿足A[ i ] + B[ j ] = c 的所有 A[ i ] 和 B[ j ]。(方法同上)
方法一:排序+二分查詢。首先,對兩個陣列中較大陣列(假設為 A)排序;然後,對 B 中每個元素 B[ i ] 在 A 中二分查詢 c - B[ i ],如果找到,直接輸出。此方法的時間複雜度為 O(mlogm + nlogm)。

方法二:排序+線性掃描。首先,對兩個陣列 A 和 B 進行排序;然後用指標 p 從頭掃描 A,用指標 q 從尾掃描 B,如果 A[ p ] + B[ q ] == c,則輸出 A[ p ] 和 B[ q ],且p++,q++;如果 A[ p ] + B[ q ] > c,則 q–;否則 p++。時間複雜度為O(mlogm + nlogn)。

方法三:hash法。首先,將兩個陣列中較小的陣列(假設為A)儲存到hash表中,然後,對於 B 中的每個元素 B[ i ],也採用相同的hash演算法在hash表中查詢 c - B[ i ] 是否存在,如果存在,則輸出。時間複雜度為O(m + n),空間複雜度為O(min(m, n))。