Задача на поиск элемента в массиве
Имеется отсортированный массив из n целых чисел, который был циклически сдвинут неизвестное число раз. Напишите код для поиска элемента в массиве. Предполагается, что массив изначально был отсортирован по возрастанию.
32К открытий33К показов
Условие задачи
Имеется отсортированный массив из n целых чисел, который был циклически сдвинут неизвестное число раз. Напишите код для поиска элемента в массиве. Предполагается, что массив изначально был отсортирован по возрастанию.
Пример:
Ввод: найти 5 в {15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14}
.
Вывод: 8 (индекс числа 5 в массиве).
Решение
Если у вас возникла мысль о бинарном поиске, вы правы!
В классической задаче бинарного поиска х
сравнивают с центральной точкой, чтобы узнать, где находится х
— слева или справа. Сложность в нашем случае заключается в том, что массив был циклически сдвинут, а значит, может иметь точку перегиба. Рассмотрим, например, два следующих массива:
У обоих массивов есть средняя точка – 20, но в первом случае 5 находится справа от нее, а в другом – слева. Поэтому сравнения х со средней точкой недостаточно. Однако если разобраться поглубже, можно заметить, что половина массива упорядочена нормально (то есть по возрастанию). Следовательно, мы можем рассмотреть отсортированную половину массива и решить, где именно следует производить поиск – в левой или правой половине.
Например, если мы ищем 5 в Array1
, то посмотрим на крайний левый элемент (10) и средний элемент (20). Так как 10 < 20, становится понятно, что левая половина отсортирована. Поскольку 5 не попадает в этот диапазон, мы знаем, что искомое место находится в правой половине массива.
В Array2
мы видим, что 50 > 20, а значит, отсортирована правая половина. Мы обращаемся к середине (20) и крайнему правому элементу (40), чтобы проверить, попадает ли 5 в рассматриваемый диапазон. Значение 5 не может находиться в правой части, а значит, его нужно искать в левой части массива.
Задача становится более сложной, если левый и средний элементы идентичны, как в случае с массивом {2, 2, 2, 3, 4, 2}
. В этом случае можно выполнить сравнение с правым элементом и, если он отличается, ограничить поиск правой половиной. В противном случае выбора не остается, и придется анализировать обе половины.
Код выполняется за время O(log n), если все элементы будут разными (об оценке сложности алгоритмов вы можете прочитать в нашей статье). При большом количестве дубликатов алгоритм потребует времени O(n). Это объясняется тем, что при большом количестве дубликатов часто приходится обрабатывать обе половины массива (левую и правую).
Концептуально данная задача несложна, но написать идеальную реализацию достаточно трудно. Не беспокойтесь, если вы допустите пару-тройку ошибок при решении этой задачи. Из-за высокого риска смещения на 1 и других второстепенных ошибок код необходимо тщательно протестировать.
Также вы можете попробовать реализовать алгоритм поиска элемента в отсортированной матрице размером MxN. Решение найдете здесь.
32К открытий33К показов