Учитывая массив A
из N
неотрицательных чисел, мне интересно найти количество способов выбрать 5 чисел (из разных позиций в массиве), чтобы их сумма была S
.
В O(N^3)
есть простое решение:
Let H be a hash table of (sum, position of leftmost element of sum)
for i = 0, N
for j = i + 1, N
H.add(A[i] + A[j], i)
numPossibilities = 0
for i = 0, N
for j = i + 1, N
for k = j + 1, N
numPossibilities += H.get(S - (A[i] + A[j] + A[k]), k)
Где H.get(x, y)
возвращает количество элементов в хеше, сумма которых имеет тот же хеш, что и x
, а самый левый элемент которого больше k.
В качестве альтернативы мы можем добавить суммы из 3 элементов в хеш-таблицу, а затем продолжить с двумя вложенными циклами. Однако сложность остается прежней, и мы просто используем больше памяти.
Предполагая, что входы будут довольно случайными (так что хеширование наихудшего случая), есть ли алгоритм, который может решить это в O(N^2)
или, может быть, O(N^2 log N)
или даже O(N^3)
, если он выполняется во всех случаях? Я думаю, что двоичный поиск может помочь, но я не вижу, как справляться с перекрывающимися индексами.
Вышеупомянутое решение на практике намного лучше, чем наивное решение для 5-для-петель, однако у меня есть чувство, что мы можем сделать намного лучше, следовательно, этот вопрос.
Если вы можете доказать, что такой алгоритм не существует, как можно оптимизировать вышеуказанное решение?
Разъяснение:
Вышеупомянутый алгоритм действительно O(N^5)
в худшем случае, например, когда данный массив содержит ничего, кроме числа 1, и мы имеем S = 5
. В среднем, однако, метод H.get
намного ближе к O(1)
, поэтому моя средняя кубическая сложность.
Если вы реализуете это и запускаете его на 1000 случайных чисел в большом интервале (скажем 0 до Int32.MaxValue), вы увидите, что он работает относительно быстро. Тем не менее, нетрудно найти входы, для которых это занимает много времени. Даже если мы не сможем добиться этого достаточно быстро для всех равных чисел, какие оптимизации мы могли бы сделать?
При тех же предположениях, можем ли мы сделать лучше, асимптотически или, по крайней мере, на практике?