Алгоритм поиска 2-х элементов c заданной разностью в массиве

мне дан массив вещественных чисел, A. Он имеет n + 1 элементов. Известно, что существует как минимум 2 элемента массива, x и y, такие, что:

 abs(x-y) <= (max(A)-min(A))/n

Мне нужно создать алгоритм для поиска 2 элементов(если их больше, любая пара хороша) за O (n) время.

Я пытался в течение нескольких часов и я застрял, никаких намеков?

2 ответов


Ву, я понял! Фокус в Принципу Дирихле.

ОК.. думайте о числах как о точках на линии. Тогда min(A) и max(A) определить начальную и конечную точки линии соответственно. Теперь разделите эту строку на n равные интервалы длиной (max(A)-min(A))/n. Так как есть n+1 точки, две из них должны попасть в один из интервалов.

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

сам алгоритм: вы можете использовать упрощенную форму сортировки ведра здесь, так как вам нужен только один элемент на ведро (нажмите два, и все готово). Первый цикл один раз через массив, чтобы получить min(A) и max(A) и создайте целочисленный массив buckets[n] инициализируется каким-то значением по умолчанию, скажем -1. Затем перейдите на второй проход:

for (int i=0; i<len; i++) {
    int bucket_num = find_bucket(array[i]);
    if (bucket[bucket_num] == -1)
        bucket[bucket_num] = i;
    else
        // found pair at (i, bucket[bucket_num])
}

здесь find_bucket(x) возвращает округленный целочисленный результат x / ((max(A)-min(A))/n).


давайте перефразируем проблему: мы должны найти два элемента, такие, что abs(x-y) <= c, где c - константа, которую мы можем найти в O(n) времени. (Действительно, мы можем вычислить оба max(A) и min(A) в линейное время и просто назначить c=(max-min)/n).

давайте представим, что у нас есть набор ведер, так что в первом ведре элементы 0<=x<c размещаются, во втором ковше элементы c<=x<=2c помещены, etc. Для каждого элемента, мы можем определить его ведро для O(1) времени. Обратите внимание, что количество занятых ведрами будет не больше, чем количество элементов в массиве.

перебираем массив и каждый элемент в его ведро. Если в ведро мы собираемся поместить его, уже есть другой элемент, то мы только что нашли правильную пару x и y!

если мы повторили весь массив, и каждый элемент попал в свое собственное ведро, не беспокойтесь! Повторите ведра сейчас (есть не более n ведра, как мы сказано выше) и для каждого элемента ковша x, если в следующий блок y элемент такой, что abs(x-y)<=c, тогда мы нашли решение.

если мы перебрали все ведра и не нашли правильных элементов, то решения нет. OMG, я действительно скучал по этой штуке с ячейками (см. другого ответа).

ведра могут быть реализованы как хэш-карта, где каждое ведро содержит один индекс массива (размещение элемента в ведре будет выглядеть так это: buckets[ a[i] / c] = i). Мы вычисляем c на O(n) время, назначьте элементы ведрам в O(n)*O(1) времени (O(1) это доступ к хэш-карте), пересекать ведра в O(n) времени. Поэтому весь алгоритм линейный.