Найдите три элемента в отсортированном массиве, которые суммируются с четвертым элементом

Недавно мой друг получил этот вопрос интервью, который кажется нам разрешимым, но не в пределах асимптотических времен, которые, по мнению интервьюера, должны быть возможны. Вот проблема:

У вас есть массив из N целых чисел, xs, отсортированный, но, возможно, нечеткий. Ваша цель состоит в том, чтобы найти четыре индекса массива (1)(a,b,c,d) так, чтобы выполнялись следующие два свойства:

xs[a] + xs[b] + xs[c] = xs[d]

a < b < c < d

Цель состоит в том, чтобы сделать это в O (N 2) времени.

Во-первых, решение O (N 3 log (N)) очевидно: для каждой упорядоченной тройки (a,b,c) используйте бинарный поиск, чтобы узнать, можно ли найти соответствующий d. Теперь, как сделать лучше?

Одно интересное предложение интервьюера состоит в том, чтобы переписать первое условие следующим образом:

xs[a] + xs[b] = xs[d] - xs[c]

Непонятно, что делать после этого, но, возможно, мы могли бы выбрать некоторое значение поворота P и искать пару (a,b), добавляющую к P и пару (d,c), вычитая на нее. Этот поиск достаточно прост для выполнения в O (n) времени для данного P, путем поиска внутрь с обоих концов массива. Однако мне кажется, что проблема в том, что существуют N 2 такие значения P, а не только N из них, поэтому мы фактически не уменьшили размер проблемы: мы работа O (N), O (N 2) раз.

Мы обнаружили, что некоторые связанные проблемы обсуждаются онлайн в другом месте: Найти 3 числа в массиве, добавляющем к данной сумме, разрешимо в N 2 но требует, чтобы сумма фиксировалась раньше времени; приспосабливая один и тот же алгоритм, но итерация по каждой возможной сумме оставляет нас при N 3 как всегда.

Другая связанная проблема выглядит как Найти все триплеты в массиве с суммой, меньшей или равной заданной сумме, но я не уверен, какая часть материала там имеет значение здесь: неравенство, а не равенство, смешивает вещи совсем немного, и, конечно, цель фиксируется, а не изменяется.

Итак, что нам не хватает? Является ли проблема невозможной в конце концов, учитывая требования к производительности? Или есть умный алгоритм, который мы не можем определить?


(1) На самом деле проблема заключается в том, чтобы найти все такие кортежи (a,b,c,d) и вернуть количество их количества. Но я думаю, что даже найти один из них в требуемых временных ограничениях достаточно сложно.

Ответ 1

Если алгоритм должен был бы перечислить решения (т.е. наборы a, b, c и d, которые удовлетворяют условию), худшая временная сложность O (n 4):

1. Могут быть решения O (n 4)

Тривиальный пример - массив с только 0 значениями в нем. Затем a, b, c и d имеют всю свободу, пока они остаются в порядке. Это представляет собой решения O (n 4).

Но более общие массивы, которые следуют следующему шаблону, имеют решения O (n 4):

w, w, w, ... x, x, x, ..., y, y, y, ...  z, z, z, ....

С таким же количеством вхождений каждого, и:

w + x + y = z

Однако, чтобы производить только количество решений, алгоритм может иметь лучшую временную сложность.

2. Алгоритм

Это небольшое изменение уже опубликованного алгоритма, который не включает фактор H. В нем также описывается, как обрабатывать случаи, когда разные конфигурации приводят к одинаковым суммам.

  • Извлеките все пары и сохраните их в массиве X, где каждый элемент получает следующую информацию:

    a: наименьший индекс двух b: другой индекс
    сумма: значение xs[a] + xs[b]

  • В то же время сохраняйте для каждой такой пары в другом массиве Y следующее:

    c: наименьший индекс двух d: другой индекс
    сумма: значение xs[d] - xs[c]

Вышеуказанная операция имеет временную сложность O (n²)

  • Сортируйте оба массива по их элементу сумма. В случае равных значений sum порядок сортировки будет определяться следующим образом: для массива X, увеличивая b; для массива Y, уменьшая c. Сортировку можно выполнить в O (n²) O (n²logn).

[ Изменить: Я не мог доказать предыдущее утверждение O (n²) (если не сделаны некоторые предположения, которые позволяют использовать алгоритм сортировки по методу radix/bucket, который я не предполагается). Как отмечено в комментариях, в общем случае массив с элементами может быть отсортирован в O (n²logn²), который O (n²logn), но не O (n²)]

  • Пройдите оба массива в "тандем", чтобы найти пары сумм, которые равны. Если это так, необходимо проверить, что X[i].b < Y[j].c. Если это так, то это решение. Но их могло быть много, и подсчет тех, кто в приемлемое время, нуждается в особой заботе.

    Пусть m = n(n-1)/2, то есть количество элементов в массиве X (что также является размером массива Y):

    i = 0
    j = 0
    while i < m and j < m:
        if X[i].sum < Y[j].sum:
            i = i + 1
        elif X[i].sum > Y[j].sum:
            j = j + 1
        else:
            # We have a solution. Need to count all others that have same sums in X and Y.
            # Find last match in Y and set k as index to it:
            countY = 0
            while k < m and X[i].sum == Y[j].sum and X[i].b < Y[j].c:
                countY = countY + 1
                j = j + 1
            k = j - 1
            # add chunks to `count`:
            while i < m and countY >= 0 and X[i].sum == Y[k].sum:
                while countY >= 0 and X[i].b >= Y[k].c:
                    countY = countY - 1
                    k = k - 1
                count = count + countY
                i = i + 1

Обратите внимание, что хотя есть вложенные циклы, переменная i только увеличивается, а значит j. Переменная k всегда уменьшается в самом внутреннем цикле. Хотя он также получает более высокие значения для начала, он никогда не сможет адресовать один и тот же элемент Y больше, чем постоянное число раз, через индекс k, поскольку, уменьшая этот показатель, он остается в пределах "той же суммы" Y.

Итак, это означает, что эта последняя часть алгоритма работает в O (m), которая O (n²). Поскольку мое последнее редактирование подтвердило, что шаг сортировки не O (n²), этот шаг определяет общую временную сложность: O (n²logn).

Ответ 2

Таким образом, одно решение может быть:

Перечислите все значения x [a] + x [b], такие, что a < b и хэш их таким образом

key = (x[a]+x[b]) and value = (a,b).

Сложность этого шага - O (n ^ 2)

Теперь Список всех x [d] - x [c] значений, таких, что d > c. Также для каждого x [d] - x [c] выполните поиск в своей карте хэша путем запроса. У нас есть решение, если существует такая запись, что c > b для любого попадания. Сложность этого шага - O (n ^ 2) * H.

Где H - время поиска в вашей хэш-карте.

Общая сложность - O (n ^ 2) * H. Теперь H может быть O (1). Это может быть сделано, если диапазон значений в массиве мал. Также выбор хэш-функции будет зависеть от свойств элементов в массиве.