Алгоритм поиска 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)
времени. Поэтому весь алгоритм линейный.