Три месяца назад мне задали интересный вопрос по алгоритму, долго думал, прежде чем придумал, теперь пишу блог, чтобы его записать.
Учитывая очень длинный массив arr, известна длина массива и длина >= 3, известно, что первый элемент массива не больше второго элемента, а последний элемент массива не больше предпоследнего элемент. Затем найдите этот массивлюбойИндексы массива пиков. PS: Элементы, которые не меньше предыдущего элемента и не меньше последнего элемента, называются гребнями.
arr[1] >= arr[0]
, то просто нужноarr[1] >= arr[2]
1 — пик.
еслиarr[1] < arr[2]
, то просто нужноarr[2] >= arr[3]
2 - пик.
...
На самом деле это может быть абстрагировано в задачу динамического программирования. Но это не обязательно и, очевидно, все равно нужно пройти после абстракции...
Подождите... что, если массив с удаленными первым и последним элементами является последовательно увеличивающимся массивом, и в этом случае нам нужно очистить весь массив, заплатив сложность O (N). Думаете, это немного похоже на серию махинаций, каждый раз, когда указатель перемещается к элементу, удовлетворяющему первой части условий гребня волны (не меньшему, чем предыдущий элемент), мы радостно ожидаем, что он удовлетворяет условиям второй половины, но иногда это не сбывается.
Вы когда-нибудь задумывались о бинарном поиске?
Действительно, это очень похоже на проблему, которую может решить бинарный поиск. ноМассивы не говорят, что они упорядочены.. Поэтому основные условия бинарного поиска вообще не выполняются.
С мертвой лошадью нужно обращаться как с живой лошадью-врачом?
Что ж, тогда попробуем. Берем элемент в самой середине массива, который называемarr[length/2]
.
Получив его, не должны ли мы безнадежно сравнивать его с его левым и правым элементами? Поскольку это сравнение происходит с массивами, накладные расходы незначительны.
Если он больше, чем левый и правый, то это, очевидно, гребень волны, тогда верните его индекс в это время.length/2
Вот и все.
Так что, если он меньше, чем тот, что слева, или меньше, чем тот, что справа, или меньше, чем оба?
Так можно ли найти гребень волны слева или справа, и как определить, что гребень волны должен быть слева или справа?
В это время мы должны заметить две проблемы.
- Если он меньше, чем тот, что слева, то
arr[:length/2+1]
Этот подмассив также является массивом, отвечающим условиям, заданным вопросом. Если он меньше, чем тот, что справа, тоarr[length/2:]
Этот подмассив также является массивом, отвечающим условиям, заданным вопросом. - Обязательно ли найдется гребень, если посмотреть налево или направо? Другими словами, обязательно ли в массиве есть хотя бы один пик, удовлетворяющий заданным условиям?
Если обратить внимание на эти две проблемы, то эта проблема решаема.
Приведите пример кода (чистый почерк...)
def find_peak(arr, length):
if length < 3:
return -1
middle = length / 2
if length < 5:
return middle
if arr[middle] > arr[middle - 1] and arr[middle] > arr[middle + 1]:
return middle
if arr[middle] < arr[middle - 1]:
return find_peak(arr[:middle + 1], middle + 1)
sub_length = middle + 1
if length % 2 == 0:
sub_length = middle
return find_peak(arr[middle:], sub_length)
Эта реализация кода должна учитывать множество границ, возможно, мой код этого не учел, если есть проблема, добро пожаловать, чтобы сделать кирпич.