Ищем алгоритм (версия 2-х мерного бинарного поиска) - PullRequest
7 голосов
/ 02 августа 2011

Простая задача и известный алгоритм:

У меня большой массив из 100 членов. Первые X членов равны 0, а остальные 1. Найдите X.

Я решаю это с помощью бинарного поиска: проверяю член 50, если он равен 0 - проверяю член 75 и т. Д., Пока не найду смежные 0 и 1.

Я ищу оптимизированный алгоритм для той же задачи в двух измерениях:

У меня есть двумерный массив 100 * 100. Те элементы, которые находятся в строках 0-X И в столбцах 0-Y, равны 0, а остальные - 1. Как найти Y и X?

Ответы [ 4 ]

10 голосов
/ 02 августа 2011

Редактировать: оптимальное решение состоит из двух простых двоичных поиска.

Мне очень жаль за длинный и запутанный пост, который я сделал ниже. В чем состоит основная проблема - найти точку в пространстве, содержащую 100 * 100 элементов. Лучшее, что вы можете сделать, это разделить на каждом шаге это пространство на две части. Вы можете сделать это запутанным способом (тот, который я делал в остальной части поста) Но если вы понимаете, что бинарный поиск по оси X все еще делит пространство исследования на два на каждом шаге (то же самое касается Y ось), тогда вы понимаете, что это оптимально.

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


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

Однако, если вам нужен оптимальный алгоритм, вы можете искать границу на X и Y одновременно. (Следует заметить, что оба алгоритма имеют одинаковую асимптотическую сложность, но оптимальный алгоритм все равно будет быстрее)

На всех следующих рисунках точка (0, 0) находится в нижнем левом углу.

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

Choosing a point in 2D

Если вы выберете точку (черный крест) и в результате получите 1 (красные линии), это означает, что искомая точка может не находиться в сером поле (таким образом, в оставшейся белой области)

enter image description here

С другой стороны, если значение равно 0 (синие линии), это означает, что искомая точка может не находиться в серой области (следовательно, должна находиться в оставшейся белой области )

enter image description here

Итак, если вы получите один результат 0 и один результат 1, это то, что вы получите:

enter image description here

Точка, которую вы ищете, находится в прямоугольнике 1, 2 или 3. Вам просто нужно проверить два угла прямоугольника 3, чтобы узнать, какой из 3 прямоугольников является хорошим.

Итак, алгоритм следующий:

  • Обратите внимание, где находятся нижний левый и верхний правый угол прямоугольника, с которым вы работаете.

  • Выполняйте бинарный поиск по диагонали прямоугольника , пока не наткнетесь хотя бы один раз на результат 1 и один раз на результат 0.

  • Отметьте 2 других угла прямоугольника 3 (вам необходимо уже знать значения двух углов по диагонали) Можно проверить только один угол, чтобы узнать правильный прямоугольник (но вы необходимо проверить два угла, если правый прямоугольник является прямоугольником 3)

  • Определите, находится ли искомая точка в прямоугольнике 1, 2 или 3

  • Повторите, уменьшая задачу до хорошего прямоугольника, пока последний прямоугольник не уменьшится до точки: это значение, которое вы ищете


Редактировать: если вы хотите оптимальности супремума, вы не хотите, когда выбираете точку (50, 50), вы не сокращаете пространство в равной части. Один в три раза больше другого. В идеале вы должны выбрать точку, которая разрезает пространство в двух равных областях (по площади)

Вы должны вычислить один раз в начале значение factor = (1.0 - 1.0/sqrt(2.0)). Затем, если вы хотите вырезать между значениями a и b, выберите точку обрезки как a + factor*(b-a). Когда вы обрезаете исходный прямоугольник 100x100 в точке (коэффициент 100 *, коэффициент 100 *), две области будут иметь площадь (100 * 100) / 2, поэтому сходимость будет быстрее.

8 голосов
/ 02 августа 2011

Запустите бинарный поиск дважды. Сначала определите X, запустив двоичный поиск в последней строке, а затем определите Y, запустив двоичный поиск в последнем столбце.

5 голосов
/ 02 августа 2011

Простое решение: идти сначала в направлении X, а затем в направлении Y.

Проверка (0,50);Если это 0, проверьте (0,75);пока Вы не найдете смежные 0 и 1. Затем идите оттуда в направлении Y.

Второе решение:

Проверьте участника (50,50).Если это 1, проверяйте (25,25), пока не найдете 0. Продолжайте, пока не найдете смежные (X, X) и (X + 1, X + 1), которые равны 0 и 1. Затем проверьте (X, X+1) и (X + 1, X).Ни один, ни один из них не будет 1. Если ни то, ни другое закончено.Если только один, скажем, например (X + 1, X), то Вы знаете, что размер блока находится между (X + 1, X) и (100, X).Используйте двоичный поиск, чтобы найти высоту поля.

EDIT : Как заметил Крис, кажется, что простой подход быстрее.

Второй раствор (модифицированный):

Проверка элемента (50,50).Если это 1, проверяйте (25,25), пока не найдете 0. Продолжайте, пока не найдете смежные (X, X) и (X + 1, X + 1), которые равны 0 и 1. Затем проверьте (X, X+1).Если это 1, тогда выполните бинарный поиск в строке (X, X + 1) ... (X, 100).Еще делайте бинарный поиск в строке (X, X) ... (100, X).

Даже тогда я, вероятно, бью здесь мертвую лошадь.Если будет быстрее, то на ничтожную сумму.Это просто для теоретического веселья.:)

РЕДАКТИРОВАТЬ 2 Как выразились Фезвез и Крис, бинарный поиск делит пространство поиска на два наиболее эффективно;Мой подход делит площадь на 1/4 и 3/4 штуки.Фезвез отметил, что это можно исправить, предварительно рассчитав коэффициент деления (но это будет дополнительный расчет).В модифицированной версии моего алгоритма я выбираю направление, куда идти (направление X или Y), которое также эффективно делит пространство поиска на две части, и затем выполняю двоичный поиск.В заключение, это показывает, что этот подход всегда будет немного медленнее.(и сложнее в реализации.)

Спасибо, Игорь Окс, за интересный вопрос.:)

1 голос
/ 02 августа 2011

Используйте двоичный поиск по обоим измерениям и одномерному случаю:

  1. Начните с j = 50. Теперь 1-D массив, полученный путем изменения i, имеет желаемую форму - так что найдите X из 1D случая.
  2. Если X = 100 (т.е. нет), тогда сделайте j = 75 (середина диапазона в измерении j) и повторите.
  3. Если X <100, значит, вы его нашли. Осталось только исправить i = X и найти Y в одномерном случае. </li>
...