Хранение парных сумм в линейном пространстве
Если у нас есть два массива размера n каждый и они хотят отсортировать их суммы, наивный подход состоял бы в том, чтобы хранить их суммы в O (n ^ 2) пространстве и сортировать его в O (n ^ 2 logn) времени. Предположим, что нам разрешено иметь одинаковое время работы O (n ^ 2 logn), как бы мы могли хранить суммы в линейном пространстве O (n)?
Я предполагаю, что мы не собираемся хранить все суммы, так как они n ^ 2 элемента не будут вписываться в n пространство и что мы просто распечатываем все в отсортированном порядке, так это значит, что мы должны динамически хранить предметы? Любые советы?
(это домашняя проблема)
Ответы
Ответ 1
Проблема, насколько я понимаю, заключается в том, что мы хотим найти суммы
a1 + b1 a1 + b2 ... a1 + bn
a2 + b1 a2 + b2 ... a2 + bn
... ... ... ...
an + b1 an + b2 ... an + bn
и распечатайте их в отсортированном порядке.
Ограничение заключается в использовании только O (n) памяти и O (n ^ 2 log n) времени в процессе.
Рассмотрим приведенную выше таблицу как n
списки (строки) элементов n
.
Если мы отсортируем исходные массивы так, чтобы a1 <= a2 <= ... <= an
и b1 <= b2 <= ... <= bn
, каждый список уже отсортирован.
Теперь проблема сводится к объединению отсортированных списков n
.
Чтобы разработать это, подумайте о том, как объединить два отсортированных списка (как в MergeSort), затем три списка и т.д.
Это тривиально распространяется на объединение n
списков длины n
в каждом из операций n
для каждого выходного элемента, в общей сложности O (n^3)
.
Теперь, что осталось, это сократить время для получения каждого выходного элемента до O (log n)
.
Когда вы попросите намек, но не полное решение, посмотрите, можете ли вы сами справиться с этим шагом.
Ответ 2
В python вы можете что-то вроде этого:
import heapq
a = [2, 1, 3]
b = [4, 6, 5]
a.sort()
b.sort()
def add_to_b(x):
for v in b:
yield v + x
for v in heapq.merge(*[add_to_b(x) for x in a]):
print v
Результат:
5
6
6
7
7
7
8
8
9
Идея состоит в том, что мы сортируем оба массива. Затем, добавляя к b
, элемент из a
определяет генератор возрастающих чисел. Поэтому мы создаем n
такие генераторы, и мы объединяем их с помощью heapq.merge
. Генератор, представленный функцией add
выше, в определенное время требует постоянного пространства (пространство, необходимое для сохранения текущей позиции в b
). heapq.merge
сам нуждается в линейном пространстве. Поэтому нам нужно линейное пространство для выполнения алгоритма.
Ответ 3
Сначала соберите 2 массива в порядке возрастания, временная сложность 2 * O(n*lgn)
, которую можно также рассматривать как O(n*lgn)
. Затем используйте максимальную кучу с длиной n + 1
для поддержания минимальных n сумм.
Как поддерживать минимальные n сумм? Сначала наведите кучку a1 + b1
, a1 + b2
, a1 + b3
,..., a1 + bn
. Затем для каждого a[i], 1 <= i < n
и b[j], 0 <= j < n
нажмите a[i] + b[j]
, а затем нажмите самый большой из них:
for(int j=0;j<n;j++) {
heap.push_into(a[0] + b[j]);
}
for(int i=1;i<n;i++) {
for(int j=0;j<n;j++) {
heap.push_into(a[i] + b[j]);
heap.pop(); // remove the current largest sum in the heap, then the sums remain in the heap are the smallest n sums
}
}
Тогда n элементов в куче - наименьшие n сумм.
Сложность времени O(n^2 * lgn)
, сложность пространства O(n)
.