[英]Pairwise sum of n numbers in non increasing order
設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]
必須是0
到B[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]
介於0
和B[0]/2-1
之間的事實一起給出了A[0]
測試的幾種可能性。
例如, A[0]
有兩種可能: 0
或1
。 如果我們嘗試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 + 3
和13 = 4 + 9
)
下一個最低輸入(5)僅與第一個(1)中的一個加數不同,因此您可以通過取差(5-1)來計算其中一個加數。
我想,在他刪除答案之前,費迪南德貝耶走在了正確的軌道上。 重復他的部分方法:你有四個未知數, a
, b
, c
和d
, a ≤ 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 + b
, a + c
, a + d
, b + c
, b + d
和c + d
。 然后可以按照費迪南德的原始計划輕松解決聯立方程。
不幸的是,有一對( a + d
, b + 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.