Две пары чисел с одинаковой суммой

приведенный список [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-подмножество с фиксированным размером подмножества:

  1. сортировка списка.
  2. использовать a приоритетная очередь для элементов, содержащих a_w + a_x как ключ и w, x в качестве значений. Предварительно заполните эту очередь n-1 элементы, где x = 0 и w = 1 .. Н-1.
  3. неоднократно поп-минимальный элемент (sum, w, x) из этой очереди и поставить элемент (a_w + a_x_plus_1, w, x+1) в очередь (но не ставьте элементы, когда x >= w). Остановка, когда два последовательных элемента, удаленных из очереди, имеют одинаковую сумму.
  4. для обработки дубликатов можно сравнить 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) для памяти.