Две пары чисел с одинаковой суммой
приведенный список [a_1 a_2 ... a_n]
(не обязательно различных) целых чисел, определить, существуют ли попарно различные индексы w,x,y,z
такое, что a_w + a_x = a_y + a_z
.
Я знаю, что один из способов-использовать 4 уровня for
циклы, каждый из которых повторяет один из индексов. Когда мы получим равные суммы, проверьте, все ли индексы попарно различны. Если да, то возвращайтесь!--4-->. Если мы исчерпали все возможности, вернуть false
. Это время O(n^4)
.
Can у нас лучше получается?
3 ответов
вычислить все возможные значения a_w + a_x
вставить их в хэш-таблице. Вставьте (a_w + a_x, w) и (a_w + a_x, x) во вторую хэш-таблицу.
перед вставкой значения в первую хэш-таблицу проверьте, находится ли оно уже в таблице. Если да, проверьте вторую таблицу. Если есть (a_w + a_x, w) или (a_w + a_x, x), ничего не вставляйте (у нас есть дубликат элемента). Если ни одна из этих пар не находится во второй таблице, у нас есть положительный ответ.
If, после обработки все (w, x) пары, у нас нет положительного ответа, это означает, что нет таких попарно различных индексов.
сложность времени O (n2). Требования к пространству также O (n2).
можно сделать то же самое в o(n) пространстве, но O(n2 * log (n)) время с немного измененным алгоритмом из этого ответа: Sum-подмножество с фиксированным размером подмножества:
- сортировка списка.
- использовать a приоритетная очередь для элементов, содержащих
a_w + a_x
как ключ иw, x
в качестве значений. Предварительно заполните эту очередьn-1
элементы, где x = 0 и w = 1 .. Н-1. - неоднократно поп-минимальный элемент
(sum, w, x)
из этой очереди и поставить элемент(a_w + a_x_plus_1, w, x+1)
в очередь (но не ставьте элементы, когда x >= w). Остановка, когда два последовательных элемента, удаленных из очереди, имеют одинаковую сумму. - для обработки дубликатов можно сравнить w, x двух последовательных элементов, имеющих равную сумму. Но проще использовать идею крямпани о предварительной обработке. Если отсортированный список содержит две пары дубликатов или один элемент дублируется 4 раза, успех. В противном случае дублируется не более одного значения; оставьте только один экземпляр в списке и добавьте его удвоенное значение в очередь приоритетов вместе с "специальной" парой индексов: (2a, -1, -1).
решение Евгения может быть несколько упрощено путем предварительной обработки исходного массива следующим образом.
мы сначала использовать хэш-таблицу для подсчета частоты каждого элемента в исходном массиве. Если хотя бы 2 элемента имеют дубликаты (их частота не менее 2) или если элемент встречается с частотой не менее 4, Ответ true
. В противном случае, если элемент a
возникает с частотой 2 или 3, мы добавляем 2a
во вторую хэш-таблицу и замените все копии a
С одна копия в исходном массиве.
затем в модифицированном массиве для каждой пары индексов i
, j
С i < j
добавляем a_i + a_j
ко второй хэш-таблице и return true
Если мы найдем дубликат записи в этой хэш-таблице.
Если у вас есть 8,5 Гб памяти (больше для беззнаковых ints, меньше, если суммы или индексы не охватывают весь диапазон int), создайте три массива. Сначала используется 1 бит на каждую возможную сумму. Это растровое изображение результатов. Second использует 32 бита на каждую возможную сумму. Он записывает индекс j. Третий использует 1 бит на каждую возможную сумму. Это битовое поле, которое записывает, если эта сумма была обнаружена в текущей итерации i -- zero ее с каждой итерацией. Повторите i=0...n и j=i+1...n. Для каждой суммы, посмотрите, если это устанавливается в первом битовом поле (если оно встречалось ранее). Если это так, посмотрите, соответствует ли индекс, записанный во 2-м массиве, i или j (Если старый j соответствует новому i или новому j). Если это не так, проверьте, что бит во 2-м массиве установлен (если он был установлен в текущей итерации и, следовательно, старый i соответствует новому i). Если нет, у вас есть спички! (Старый я никогда не буду соответствовать старому j или новому j, и новый я никогда не буду соответствовать новому j.) Выход. В противном случае запишите сумму во все три массива и продолжать.
хотя он использует память стоимостью $ 40 (мне нравится настоящее:), это, вероятно, намного быстрее, чем использование хэш-карт и бокса. Может даже использовать меньше памяти для больших n. Одним из недостатков является то, что данные почти никогда не будут в кэше L2. Но попробуйте настроить JVM на использование огромных страниц, чтобы по крайней мере TLB miss не переходил в основную память. Это o (n^2) для обработки и o(1) для памяти.