2016-11-10 2 views
2

Скажите, что есть два отсортированных списка: A и B.Каков самый быстрый алгоритм для пересечения двух отсортированных списков?

Количество записей в A и B может варьироваться. (Они могут быть очень маленькими/огромными. Они могут быть похожими друг на друга/существенно отличаются).

Как известно, это самый быстрый алгоритм для этой функции?

Может ли кто-нибудь дать мне идею или ссылку?

+1

Вы можете выполнить его в O (nlog (n)), применяя двоичный поиск в списке A для всех элементов в списке B. Если размер списков очень отличается, то желательно искать в большем списке. – Shubham

+0

кажется, что у вас плохой подход. Почему вы спрашиваете о самом быстром алгоритме вместо того, чтобы разрабатывать свои собственные, которые не предпринимали бы лишних шагов? – xenteros

+0

@syko Я дал вам рабочий код ниже – xenteros

ответ

3

Предположим, что A имеет m элементы и B имеет n элементы, с m ≥ n. Информация теоретически, лучшее, что мы можем сделать, это

(m + n)! 
lg -------- = n lg (m/n) + O(n) 
    m! n! 

сравнения, так как для того, чтобы проверить пустое пересечение, мы по существу должны выполнить отсортированный слияния. Мы можем получить постоянный коэффициент этой привязки путем повторения через B и сохранения «курсора» в A с указанием позиции, в которой должен быть вставлен последний элемент B для поддержания упорядоченного порядка.Мы используем exponential search для перемещения курсора, на общую сумму, которая по заказу

lg x_1 + lg x_2 + ... + lg x_n, 

где x_1 + x_2 + ... + x_n = m + n есть некоторое целое число раздел m. Эта сумма составляет O(n lg (m/n)) по объему lg.

0

Допустим, есть 2 Списки А и В с целыми

for(int i = A.size() - 1; i > -1; --i){ 
    Integer currentInteger = A.get(i); 
    if(!B.remove(currentInteger)) 
     A.remove(currentInteger); 
} 
2

Я не знаю, если это самый быстрый вариант, но вот один, который работает в O(n+m) где n и m являются размеры списков:

  • Цикл по обоим спискам, пока один из них не опустеет следующим образом:
  • Advance один на один список.
  • Перейдите в другой список, пока не найдете значение, равное или большее, чем текущее значение другого списка.
  • Если он равен, элемент принадлежит к перекрестку, и вы можете добавить его в другой список.
  • Если это больше, чем другой элемент, перейдите в другой список, пока не найдете значение, равное или большее, чем это значение
  • как сказал, повторять это, пока один из списков пуст
+3

Это естественно и может даже быть оптимальным для * связанных * списков (где линейное сканирование неизбежно). С другой стороны, если возможен произвольный доступ (как и в списках Python, которые действительно являются массивами), то то, что использует бинарный поиск для поиска следующего общего элемента, может быть лучше, что заметно, когда списки большие, а пересечение невелико. Кажется, трудно сказать, что лучший подход, не зная немного больше о списках. –

+0

@JohnColeman Это правильно. Мой ответ основан на предположении, что OP говорил о связанных списках, которые не поддерживаются массивами внутри (например, ArrayList Java или массивы/списки во многих других языках программирования), так что доступ к элементам невозможен в O (1). – Keiwan

0

Что такое, как известно, самый быстрый алгоритм для этой функции?

Используйте merge sort метод, который лучше всего, когда два списка отсортирован. Для получения объединенного списка сортировки потребуется O(n+m).

Вы не можете сортировать эти два списка без прохождения каждого из них. Таким образом, лучшее, что вы можете достичь, - O(n+m).

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

+0

Предположение о том, что списки уже отсортированы. Если один список состоит из 100 нечетных чисел, а другой состоит из 1 000 000 000 четных чисел, он не должен принимать 1,000,000100 шагов, чтобы определить, что их пересечение пуста, поэтому я сомневаюсь, что «O (m + n)» является оптимальным. –

+0

Ques - это то, как вы будете использовать случайный доступ в связанном списке, а также редко будете знать заранее тип или шаблон списка. Итак, разве это не применимый сценарий для списка? –

+0

OP не был явно связан с связанными или несвязанными списками. Если это списки произвольного доступа, и вы знаете их размеры, лучшим может быть выбор между 1 из 3 алгоритмов, в зависимости от того, какие из 'm + n',' m * log (n, 2) 'и' n * log (m, 2) 'наименьшее. 100 раз логарифм базы 2 составляет 1 000 000 100 меньше, чем 3000, что на порядки меньше 1 000 000 100, поэтому для этих размеров простой подход слияния не так хорош, как последовательный двоичный поиск 100 элементов в большем списке. Если он будет реализован правильно, самый первый поиск остановится с окончательным ответом, так как пересечение пусто. –

Смежные вопросы