2017-06-06 80 views
0

幾周前我有一次求職面試,我被要求設計一個分而治之算法。我無法解決問題,但他們只是打電話給我第二次面試!這裏是一個問題:我們給出了兩個n元素數組A [0..n-1]和B [0..n-1](其中 不一定是整數),一個整數值。給出一個O(nlogn)分而治之算法,它確定是否存在不同的值i,j(即i!= j),使得A [i] + B [j] =值。如果i,j存在,那麼你的算法應該返回True,否則返回False。你可以假設A中的元素是不同的,而B中的元素是不同的。分而治之算法

任何人都可以解決這個問題嗎?謝謝

+1

你是怎麼試着解決這個問題的?你卡在哪裏? –

+0

如果我們不使用分而治之(蠻力),這是非常容易的。但我不知道如何使用分治法來解決這個問題。我希望如果有人至少可以給我暗示 –

+0

「如果存在不同的值I,J(即I = J 1)」:這是一個非常可疑的要求。由於元素是從不同的數組中抽取出來的,所以要求使用不同的索引是毫無意義的,而不同的值不是由i!= j表示,而是由A [i]!= B [j]表示。另一種解釋可能是「是否有不同的對,如......」。 –

回答

0

下面的算法不使用分而治之,但它是解決方案之一。 您需要對兩個數組進行排序,並維護元素的索引,以排序(elem, index)對的數組。這需要O(n log n)時間。

然後,您可以應用合併算法來檢查是否存在兩個元素,例如A [i] + B [j] = value。這將O(n)

總體時間複雜度將是O(n log n)

+0

D&C在哪裏? –

+0

我的算法中沒有D&C。我剛發佈了一個可能的解決方案我會相應地編輯我的答案。 –

0

我的做法是..

  1. 排序任意陣列。這裏我們對數組A進行排序。使用算法對其進行排序,該算法是Divide and Conquer算法。
  2. 然後對於B的每個元素,通過Binary Search在數組A中搜索Required Value- Element of B。這又是一個Divide and Conquer算法。
  3. 如果您從數組A中找到元素Required Value - Element of B,那麼Both元素使得對的數目爲Element of A + Element of B = Required Value

所以這裏的時間複雜度,AN元素,因此Merge Sort將採取O(N log N)和我們爲這需要O(N log N) B的每一個元素(總氮元素)做Binary Search。所以總的時間複雜度將是O(N log N)

正如你所說的,你需要檢查i != j如果A[i] + B[j] = value然後在這裏你可以採取二維數組的大小N * 2。每個元素都與其原始索引配對,作爲每行的第二個元素。根據存儲在第一個元素中的數據完成排序。然後,當您找到元素時,您可以比較兩個元素的原始索引並相應地返回值。

0

我建議使用哈希。即使它是而不是你應該解決這個問題,值得一提的是,哈希算法具有更好的時間複雜度O(n) v。O(n*log(n))這就是爲什麼更高效。

  1. 打開AHashSet的(或字典如果我們想i指數) - O(n)
  2. 掃描B並檢查是否有在HashSet中的value - B[j](字典) - O(n)

所以你有一個O(n) + O(n) = O(n)算法(這是更好需要(O n * log(n)),然而,該解決方案是不分而治之):

樣品C#實現

int[] A = new int[] { 7, 9, 5, 3, 47, 89, 1 }; 
    int[] B = new int[] { 5, 7, 3, 4, 21, 59, 0 }; 

    int value = 106; // 47 + 59 = A[4] + B[5] 

    // Turn A into a dictionary: key = item's value; value = item's key 
    var dict = A 
    .Select((val, index) => new { 
     v = val, 
     i = index, }) 
    .ToDictionary(item => item.v, item => item.i); 

    int i = -1; 
    int j = -1; 

    // Scan B array 
    for (int k = 0; k < B.Length; ++k) { 
    if (dict.TryGetValue(value - B[k], out i)) { 
     // Solution found: {i, j} 
     j = k; 

     // if you want any solution then break 
     break; 

     // scan further (comment out "break") if you want all pairs 
    } 
    } 

    Console.Write(j >= 0 ? $"{i} {j}" : "No solution"); 
+0

這個解決方案可能是迄今爲止較少的D&C。 –

+1

這是這類問題的最簡單的解決方案,但OP仍然沒有要求這樣做。 –

0

似乎很難做到不排序。

如果離開排序,則列,檢查的A[i]+B[j] = Value存在需要時間Ω(n)固定i,然後檢查所有i需要Θ(n²),除非你找到一招把一些秩序B

平衡鴻溝似乎&征服的無序排列並沒有任何好轉:如果您在兩半分AB,該解決方案能夠橫亙在Al/Bl一個,Al/BrAr/BlAr/Br這產生復發T(n) = 4 T(n/2),它有一個二次方案。

如果允許排序,Sanket Makani提供的解決方案是一種可能性,但您在搜索階段的時間複雜性方面做得更好。

事實上,假設AB現在排序,並考慮2D功能A[i]+B[j],這是在兩個方向上ij單調。然後,域A[i]+B[j] ≤ Value受單調曲線j = f(i)或等同於i = g(j)的限制。但是對於曲線的所有點必須嚴格檢查嚴格的相等性A[i]+B[j] = Value,並且在最壞的情況下無法避免在任何地方評估f

i = 0開始,通過二分搜索獲得f(i)。然後,您可以逐漸跟隨邊界曲線。您將沿着i方向執行n步驟,並且在j方向中最多執行n步驟,因此複雜度仍以最優的O(n)爲界。

下面是一個示例,顯示總和低於和高於目標值的區域(有兩個匹配項)。

enter image description here

這個最佳的解決方案有什麼與鴻溝&征服。也許可以根據對中心點求和的評估來設計一個變體,這樣就可以丟棄整個象限,但這是非常人造的。

+0

這是「開始在A的開始和B的結束一個真正令人困惑的解釋,反覆移動到下一個元素,如果總和大於目標值或B,如果是較大的,這作品的一個元素小因爲A左側的任何元素都較小,因此總和會較小,類似於B「。 – Dukeling

+0

不錯的搜索方法,但我不同意這是我提供的方法更高效。對於兩種算法'O(n log n)',時間複雜度都是相同的。如果再算上總迭代那麼你的做法有'2 * N日誌N'排序兩個陣列和'N'爲seaching而在我的做法我們也整理了只有一個陣列和另一個陣列,我們對每個元素做二進制SEACH這樣總的迭代將是'n log n + n *(log n)= 2 * n log n'。起初,你的方法似乎比我的更省時,但實際上它比我的方法開銷更多。 –

+0

@SanketMakani:我明確指定了「搜索階段」,即假設數組已排序。但僅對一個數組進行排序就足夠了。其實我的觀點表明,把兩者都排序是沒有用的。而二分搜索是過度殺傷。 –