簡體   English   中英

以非遞增順序的n個數的成對和

[英]Pairwise sum of n numbers in non increasing order

我在編程訪談博客中看到了這個問題

如果以非遞減順序給出n個數的成對和,則識別各個數字。 如果總和已損壞,則打印-1

例:

i/p: 4 5 7 10 12 13 

o/p: 1 3 4 9

提示就足夠了。

B是成對和的列表,其中B[0] <= B[1] <= ... <= B[m-1]並且讓A成為我們試圖找到的原始數字列表, A[0] < A[1] < ... < A[n-1] ,其中m = n(n-1)/2

給定A[0] ,在多項式時間內計算A

建立A從最小的元素來最大的。 假設我們已經知道A[0] 然后,由於B[0]是在最小的元素B ,它只能產生作為A[0] + A[1] 同樣, B[1]必須等於A[0] + A[2] 因此,如果我們知道A[0] ,我們可以計算A[1]A[2]

然而,在那之后,這種模式崩潰了。 B[2]可以是A[0] + A[3]A[1] + A[2] ,如果沒有先驗知識,我們就不知道它是哪一個。 但是,如果我們知道A[0] ,我們可以如上所述計算A[1]A[2] ,然后從B刪除A[1] + A[2] 然后保證下一個最小元素是A[0] + A[3] ,這允許我們找到A[3] 繼續這樣,我們可以找到所有的A而無需回溯。 算法看起來像這樣:

for i from 1 to n-1 {
    // REMOVE SEEN SUMS FROM B
    for j from 0 to i-2 {
        remove A[j]+A[i-1] from B
    }
    // SOLVE FOR NEXT TERM
    A[i] = B[0] - A[0]
}
return A

如果我們知道A[0]=1那么這就是你的例子,其中B = [4,5,7,10,12,13]

start
    B = [4,5,7,10,12,13]
    A[0] = 1

i=1: 
    B = [4,5,7,10,12,13]
    A[1] = 4-1 = 3

i=2:
    Remove 1+3 from B
    B = [5,7,10,12,13]
    A[2] = 5-1 = 4

i=3:
    Remove 1+4 and 3+4 from B
    B = [10,12,13]
    A[3] = 10-1 = 9

end
    Remove 1+9 and 3+9 and 4+9 from B
    B = []
    A = [1,3,4,9]

所以這一切都歸結為知道A[0] ,我們可以從中計算A的其余部分。

在多項式時間內計算A[0]

我們現在可以簡單地嘗試A[0]所有可能性。 由於我們知道B[0] = A[0] + A[1] ,我們知道A[0]必須是0B[0]/2 - 1之間的整數。 我們也知道

B[0] = A[0] + A[1]
B[1] = A[0] + A[2]

此外,存在一些索引i其中2 <= i <= n-1

B[i] = A[1] + A[2]

為什么? 因為可能小於A[1]+A[2]的唯一條目具有形式A[0] + A[j] ,並且最多有n-1這樣的表達式。 因此我們也知道

A[0] = (B[0]+B[1] - B[i])/2

對於某些2 <= i <= n-1 這與A[0]介於0B[0]/2-1之間的事實一起給出了A[0]測試的幾種可能性。

例如, A[0]有兩種可能: 01 如果我們嘗試A[0]=0的算法,這是發生的事情:

start
    B = [4,5,7,10,12,13]
    A[0] = 0

i=1: 
    B = [4,5,7,10,12,13]
    A[1] = 4-0 = 4

i=2:
    Remove 0+4 from B
    B = [5,7,10,12,13]
    A[2] = 5-0 = 5

i=3:
    Remove 0+5 and 4+5 from B
    B = !!! PROBLEM, THERE IS NO 9 IN B!

end

一些提示:

  • 輸入的大小為N *(N-1)/ 2,因此您可以推導出輸出的大小(即輸入中的6個元素對應於輸出中的4個元素)

  • 輸入的總和是輸出之和除以N - 1 (即1+3+4+9 = (4+5+7+10+12+13) / (4-1)

  • 最低輸入和最高輸入分別是兩個最低和兩個最高輸出的總和(即4 = 1 + 313 = 4 + 9

  • 下一個最低輸入(5)僅與第一個(1)中的一個加數不同,因此您可以通過取差(5-1)來計算其中一個加數。

我想,在他刪除答案之前,費迪南德貝耶走在了正確的軌道上。 重復他的部分方法:你有四個未知數, abcda ≤ b ≤ c ≤ d 由此,可以形成所有總和的部分排序:

a + b ≤ a + c
a + b ≤ a + d
a + c ≤ b + c
a + d ≤ b + d
a + d ≤ c + d
b + c ≤ b + d
b + d ≤ c + d

如果這是總順序,則可以知道六個值a + ba + ca + db + cb + dc + d 然后可以按照費迪南德的原始計划輕松解決聯立方程。

不幸的是,有一對( a + db + c ),可以任意方式訂購。 但這很容易處理:假設a + d < b + c (輸入值都是不同的,所以不必擔心使用≤)並嘗試求解聯立方程。 然后假設b + c < a + d並重復。 如果兩組方程都有解,那么原問題有兩個答案。 如果兩個集都沒有解,那么輸出應為-1 否則,您有(獨特的)解決方案。

最近我正在檢查面試問題,我在@ PengOne提示找到第一個價值的幫助下解決了這個問題,

因此,如果有人需要一個完整的工作解決方案:它是在PHP中:

時間復雜度:帶有輔助變量的O((n *(n-2))+ 3 + n)。 空間復雜性:幾乎與時間復雜相同。

<?php
function getSublistSize($length)
{
    $i = 2;
    $n = 0;

    while ($i <= $length) {
        if (is_int($length / $i)) {
            if ($length == $i * ($i + 1) / 2) {
                return ($i + 1);
            }
        }

        ++$i;
    }

    return $n;
}

function findSubstractList(array $list)
{
    $length = count($list);

    $n = getSublistSize($length);
    $nth = $n - 1;

    $substractList = [];
    $substractTotal = array_sum($list) / ($length / 2); // A + B + C + D

    /**
     * formula : A = (list[0] + list[1] - list[nth -1]) / 2
     * list[0] = A + B,
     * list[1] = A + C,
     * list[nth - 1] = B + C
     *
     * =>  ((A + B) + (A + C) - (B + C)) / 2
     * => (A + A + (B + C - B - C)) / 2
     * => (2A + 0) / 2 => 2A / 2
     * => A
     */
    $substractList[] = (($list[0] + $list[1]) - $list[$nth]) / 2;

    for ($i = 0; $i < $nth; ++$i) {
        $substractList[] = ($list[$i] - $substractList[0]);
    }

//    $substractList[3] = $substractTotal - ($list[$nth - 1] + $substractList[0]);


    return $substractList;
}


$list = [5, 8, 14, 28, 40, 11, 17, 31, 43, 20, 34, 46, 40, 52, 66];

print_r(findSubstractList($list));

/**
 * P ) [6, 11, 101, 15, 105, 110];
 * S ) [1, 5, 10, 100]
 *
 * P ) [5, 8, 14, 28, 40, 11, 17, 31, 43, 20, 34, 46, 40, 52, 66];
 * S ) [1, 4, 7, 13, 27, 39]
 *
*/

PengOne恢復給定A [0]和B的方法很好,但有一種更好的方法來計算A [0]。 請注意,B的兩個最小元素是:

B[0] = A[0] + A[1]
B[1] = A[0] + A[2]

B[i] = A[1] + A[2]

對於一些我。

因此,

A[0] = (B[0] + B[1] - B[i]) / 2

對於某些我來說,我們只需要嘗試O(n ^ {1/2})的可能性,因為我受到O(n ^ {1/2})的限制,看看是否有一個導致剩余的有效設置每個PengOne解決方案的元素。 總運行時間為O(n ^ {3/2}),其中n是輸入中的數字數。

我不確定最快的算法,但我可以解釋它是如何工作的。

o / p的第一個數是第一個和第二個i / p之間的差值

5-4=1

,所以現在你有第一個o / p號碼。

第二個o / p數是第一個i / p減去第一個o / p。

4-1=3

o / p的第三個是第二個o / p減去第一個i / p

5-1=4

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM