Попарные суммы n чисел в возрастающем порядке
Я видел этот вопрос в программировании блог интервью.
Если попарно суммы
n
числа задаются в неубывающем порядке, идентифицируют отдельные числа. Если сумма повреждена print-1
.
пример:
i/p: 4 5 7 10 12 13
o/p: 1 3 4 9
намека было бы достаточно.
6 ответов
пусть 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]
. Поэтому, если мы знаем!--11-->, мы можем вычислить A[1]
и A[2]
.
после этого, однако, этот шаблон ломается. B[2]
может быть A[0] + A[3]
или , мы можем вычислить A[1]
и A[2]
как описано выше, а затем удалить A[1] + A[2]
С B
. Следующий наименьший элемент тогда гарантированно будет 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
вот как это работает из вашего примера, где B = [4,5,7,10,12,13]
если мы знаем!--35-->:
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]
. Поскольку мы знаем!--40-->, мы знаем!--11--> должно быть целое число между 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)
)самый низкий входной сигнал и самые высокие входные сигналы сумма 2 самых низких и 2 самых высоких выхода соответственно (т. е.
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
. В противном случае у вас есть (уникальное) решение.
подход Пенгоне к восстановлению данных 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
для некоторых i, и нам просто нужно попробовать возможности O(n^{1/2}), так как i ограничен O(n^{1/2}), и посмотреть, приводит ли он к допустимой настройке оставшихся элементов решения пенгона. Общее время является O (n^{3/2}), где n-количество чисел на входе.
недавно я проверял вопросы интервью, и я решил проблему с помощью подсказки @PengOne для поиска первого значения,
поэтому, если кому-то нужно полное рабочее решение : Это в PHP :
сложность времени: O ((n * (n-2)) + 3 + n) с вспомогательными переменными. пространство сложность : почти то же самое с complextiy время.
<?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]
*
*/
Я не уверен в самом быстром алгоритме, но я могу объяснить, как это работает.
первое число 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