Автор оригинала: FreeCodeCapm Team.
Дивиа Годаяль
Потрясающие. Вот как я сейчас чувствую. Написание моей первой сольной технической статьи.
Должен сказать, что у меня есть много, чтобы поделиться с вами, ребята, и намного больше учиться. Так что без какого-либо дальнейшего ADO давайте доберемся до него. И да, держись на туго – потому что в сказке есть поворот. ?
Бинарный поиск
Все мы слышали о классическом 2 яйца и 100 историй проблема. У меня есть что-то подобное для вас.
У вас есть 100-летнее здание с правилом:
Люди с домашними животными могут заниматься только верхными этажами
Ваш друг пожелает купить квартиру в этом здании. Она слишком боится домашних животных, чтобы жить рядом с ними, но ты любишь их. Она спросила, сможете ли вы помочь ей выяснить, где начинается именно полы на домашних животных. Она хочет изучить все различные варианты доступными, и поэтому вам нужно выяснить, какие этажи начиная с нуля, являются теми, которые не позволяют домашним животным.
Люди для управления зданием находятся в отпуске. На каждом этаже рядом с лифтом есть подписи рядом с лифтом, говоря, если пол домашнее животное работает или нет. Но вы слишком ленивы, чтобы остановиться на каждом этаже, чтобы проверить доску знаков домашних животных, так как подъемник такой медленный.
Что вы делаете?
Лифт занимает почти минуту на каждом этаже, чтобы остановиться, а затем начать снова. Да, так это плохо. Но между этажами навигация довольно гладкая. Вы должны сделать это быстро.
Как вы идете об этом?
Итеративный подход
Один наивный подход к этому будет начать в самом нижней части здания (первого этажа) и продолжать останавливать подъем на каждом этаже, чтобы проверить знак, который опубликовал этот этаж. Вы останавливаетесь, когда найдете подписать домашнее животное.
Лучший случай Это то, что на первом этаже есть знак домашних животных. Это означает, что все здание имеет домашние животные. Ни в коем случае твой друг не купил бы квартиру здесь.
Средний случай В том, что вы идете на 50-й этаж, остановив на каждом этаже между и, наконец, найдут доску для знака питомца. Таким образом, твой друг может купить один из 1-49.
Худший случай Сценарий, когда вы достигли 100-го этажа, останавливаясь на каждом этаже на пути, только чтобы выяснить, что во всем здании нет знаков для домашних животных. Таким образом, твой друг может купить любую квартиру от 1 до 100, но кто заботится, потребовалось почти два часа, чтобы найти это. ? Вспомогательный
Алгоритмично, учитывая массив из 100 логических ценностей, индекс массива представляет собой строительные этажи, а 0 представляет собой пол, когда домашние животные не допускаются, в то время как A 1 представляет собой пол, где будут разрешены домашние животные. Из правила здания, массив будет иметь форму
000... 1111...
То есть все 0, следующие всеми 1s, потому что только верхние этажи могут быть теми, где допускаются домашние животные.
Учитывая этот массив, нам нужно найти первый индекс, где есть 1
Отказ Алгоритм линейного поиска для этой проблемы был бы таким же простым, как игре по массиву и ищете 1
и возвращение, когда мы находим один.
Как и ожидалось, сложность этого алгоритма будет O (n)
Где для нашего конкретного примера здания. Вам нужно придумать что-то быстрее, чем это. Остановка на каждом этаже не осуществимо, так как вам принесет вас много времени, чтобы покрыть все здание в худшем случае.
Бинарный поиск подход
Допустим, вы начнете с первого этажа и добрались до 50-го этажа без остановок. На 50-м этаже вы остановились и вышли из подъема и проверили на знак. Знак доски сказал "Нет домашних животных"
Отказ Это будет означать, что до 50-го этажа определенно нет домашних животных.
Так что теперь зная, что вы уменьшаете свое поисковое пространство на другую половину, что это полы 51-100. Это означает, что с одной остановкой вы смогли покрыть половину здания, зная наверняка, что первая половина не имеет домашних животных. Это восхитительно!
Двигаясь, вы снова разделите свой оставшийся набор этажей пополам и возьмите подъемник и переходите прямо на 75-й этаж. И вы видите «Домашние животные»
Подпишитесь там. Это означает, что этаж, где он начал появиться, должно быть между 50-75. Вы можете следить за аналогичным подходом погружения оставшихся пола на половину и проверку, пока не найдете первого этажа с «Домашние животные»
Знак доска.
Вы видите, каждый раз, когда вы принимаете решение, вы разделяете ваше поисковое пространство на две половины и продвигайтесь с одной половиной пространства поиска. Вот как мы сужаем наш поиск. Поскольку мы всегда разделяем пространство поиска в два и выбираем один над другим, поэтому эта стратегия поиска называется Бинарный
Стратегия поиска.
Разве это не быстрее?
Давайте посмотрим в алгоритм для этого.
Если вы внимательно следили в тесном режиме и похвалю алгоритма, вы бы реализовали жесткое и быстрое условие для работы двоичного поиска алгоритма. Состояние состоит в том, что массив должен быть отсортирован заранее. В нашем примере строительные этажи были отсортированы с 1-100, и мы могли бы легко разделить пространство поиска в два.
Давайте посмотрим на примерный массив, который сортируется и попробуйте искать элемент в нем.
В приведенном выше примере элемент для поиска – 8. Данный массив является отсортированным массивом в увеличении порядка. Как только мы найдем средний элемент (который 5), мы видим, что поиск элемента больше, чем текущий элемент индекса. Поскольку массив отсортирован в увеличении порядка, 8 будет лежать справа от массива и никогда не может быть на левой стороне.
Поэтому мы игнорируем элементы слева от 5 и продолжайте поиск оставшихся элементов, в конечном итоге выясним 8.
С другой стороны, что если массив не отсортирован? Несмотря на то, что мы знаем текущий элемент 5, и мы знаем, что нам нужно искать 8, мы не уверены, какой направление является правильным способом. Если мы в конечном итоге мыслить, что массив отсортирован и применяет двоичный поиск и перейти к подходящей части, мы никогда не найдем 8.
Таким образом, бинарный поиск по существу хочет, чтобы ваш массив был отсортирован.
Это был стандартный алгоритм двоичного поиска, на котором мы только что посмотрели. Но, поскольку название статьи предлагает, в сказке есть поворот!
Я заядлый конкурентный программист, и был интересный вариант алгоритма двоичного поиска в CODECHEF может долго вызов Отказ
По сути, шеф-повар написал классический двоичный поиск, предполагая, что входной массив будет отсортирован. Все остальные дети в классе скопировали код от него, так как шеф-повар – лучший программист в классе. Его предположение может стоить весь класс их знаков назначения, так как входной массив не отсортирован заранее.
Единственное, что шеф-повар может сделать, это предварительно обработать массив, подняв некоторые номера здесь и там так, чтобы процесса двоичного поиска по-прежнему возвращает правильный индекс.
Примечание: Препроцессор выше должен идеально вернуть модифицированный массив для бинарного поиска, чтобы правильно работать. Однако, как спрашивает заявление о проблеме, мы просто пытаемся определить количество свопов, необходимых для двоичного поиска, чтобы правильно работать на несортированном массиве, приведенном вход. Алгоритм также вернет -1, если такая модификация невозможна для данного массива и элемента.
Идея здесь очень проста.
Нам нужно понимать два основных шага. Я называю их Ti-Me шаги. Возможно, это поможет вам помнить, что мы здесь делаем.
а. T arget Я NDEX: индекс элемента для поиска. Нам нужно знать это, так как этот индекс поможет нам водить модификации. Потому что каждый раз, когда мы изменим любой элемент, нам нужно плавать в этом индексе, а не вдали от него.
б. М надпись Е Lement: Если вы ясно выглядите в двоичном поисковом поискоре, это средний элемент текущего поискового пространства, который управляет следующим ходом. Если этот средний элемент принимает нас в неправильном направлении, нам нужно заменить с помощью соответствующего элемента.
Таким образом, вся идея здесь заключается в том, что мы поменяем все средние элементы, которые ошибочно размещены.
Двоичный алгоритм поиска (значение среднего элемента относительно элемента для поиска, то есть x) может принять нас к левой половине массива или правой половины. Итак, есть две возможности для неправильно помещенного среднего элемента:
- Элемент для поиска был справа от среднего элемента, но поскольку
Элемент [середина]> Элемент [Target Ind
EX], бинарный поиск должен был бы игнорировать правую половину и двигаться к левой половине. ИЛИ ЖЕ - Элемент для поиска был слева от среднего элемента, но с
Элемент [MID] <Элемент [Target Ind
Ex], бинарный поиск должен был бы игнорировать левую половину и двигаться к правой половине.
Следовательно, если средний элемент ошибочно размещен так, что число Х
был нужен в его месте, где X
Это count_low_nee
добиваться
Точно так же, если средний элемент ошибочно размещен так, что число Х
был нужен в его месте, где X> Элемент [Target Ind
Ex], тогда мы поддерживаем счетчик для этого и позвоните Это count_high_nee
добиваться
Кроме того, если мы просто запустим алгоритм двоичного поиска над заданным массивом при поиске номеров, будут иметь некоторые числа, которые будут правильно размещены. Это были бы средние элементы, которые привели двоичный поиск в правильных направлениях, соответствующих данному элементу Х
(Элемент для поиска). Эти цифры не могут быть частью замены, потому что они правы позиционируются в отношении Х
Отказ
Давайте сначала посмотрим на псевдо-код для этого алгоритма, а затем пройдите пример.
function can_preprocess(arr, X){ low = 0 high= 0
while X is not found { mid = (low + high) / 2 if arr[mid] == X { break }
correctly_placed_low = 0 correctly_placed_high = 0 count_low_needed = 0 count_high_needed = 0
if `mid` suggests we should go right for X { if X is actually on the right { correctly_placed_low ++ } else { count_low_needed ++ } } else { if X is actually on the left { correctly_placed_high ++ } else { count_high_needed ++ } }
modify low and high according to where `X` actually is with respect to `mid`
}
// Total smaller numbers available for swapping TSM = sorted_index[X] - correctly_placed_low
// Total Larger numbers available for swapping TLM = (N - sorted_index[X]) - correctly_placed_high
if count_low_needed > TSM or count_high_needed > TLM { return -1 }
return max(count_low_needed, count_high_needed)
Примечание: Заявление о проблеме исправляет входной массив для нас и несколько раз пропускает значения, которые будут искать в массиве входных данных. Итак, мы можем протереть один раз по сравнению с исходным массивом, чтобы узнать фактическое местоположение элемента для поиска (создайте словарь, по существу).
Кроме того, нам нужно Сортировать_index [x]
сказать нам, сколько значений меньше или больше, чем элемент Х
в нашем массиве. Мы можем отсортировать массив и создать другое словаре, хранящее местоположение каждого элемента в отсортированном массиве.
Давайте пройдем шаги предложенного алгоритма во время сухого прибора.
- Учитывая несортированный массив, вам нужно искать
Х
Отказ Следовательно, наш целевой индекс составляет 7.
2. Индекс среднего элемента <Целевой индекс, поэтому нам нужно маневрировать наш поиск в правой половине. B Элемент UT [MID]> Элемент [Target
Индекс], Следовательно, Count_low_need
ред
3. Индекс среднего элемента <Целевой индекс, поэтому нам все еще нужно маневрировать наш поиск по праву. Однажды Агай n, элемент [середина]> Элемент [Target
Индекс], Следовательно, Count_low_need
ред
4. Общее количество свопов, необходимых для двоичного поиска, чтобы вернуть правильный индекс, здесь будет два свопащими с элементами ниже 4. У нас меньше числа 1, 3 или 2
Для замены доступны, чтобы мы могли успешно сделать обмен на этот массив, чтобы правильно узнать двоичный поиск 4
Отказ
Ниже приведен код Python для данной проблемы. Каждый шаг объясняется в комментариях.
Сложность времени этого витой двоичного алгоритма поиска все еще O (nlogn)
Отказ
Я надеюсь, что вы смогли понять внутреннюю работу двоичного алгоритма поиска и веселились, когда проходите эту интересную проблему. Если вы нашли этот пост полезным, распространите любовь и делитесь как можно больше. ?