Модуль: Бинарный (двоичный) поиск по ответу


Задача

2/8

Бинарный (двоичный) поиск по ответу (Python)

Теория Нажмите, чтобы прочитать/скрыть

Бинарный (двоичный) поиск по ответу

Существует класс задач, в которых мы можем быстро проверять является ли какое-либо значение ответом к задаче или нет. Но сам ответ быстро найти не можем. При этом, мы можем сказать, что ответ всегда лежит в определенных границах. Кроме этого, если перебирать значения линейным перебором (от минимально возможного до максимального возможного) и проверять подходит ли нам это значение в качестве ответа, то мы будем получать такие ответы: нет нет ... нет да да ... да (или наоборот, сначала да, потом нет).
В этом случае, мы можем для поиска ответа использовать двоичный поиск. 
 

Основная идея решения задачи методом двоичного поиска заключается в том, чтобы сформулировать задачу "найдите максимальное (минимальное) X, такое что какое-то свойство от X выполняется" и решить её, подбирая значение X бинпоиском.

Обычно, для нахождения ответа методом двоичного поиска, создают отдельную функцию, которая проверяет может ли являться переданное значение ответом или нет и возращает True или False.
Сам двоичный поиск будет выглядеть следующим образом (приведем 2 варианта реализации, которых достаточно для решения любой задачи).
# Функция check() возвращает 
# сначала True, потом False
# Необходимо найти 
# последний check() == True

l = 0
r = ??? # определяется из условия
while l + 1 < r:
  m = (l + r) // 2
  if check(m):
    l = m
  else:
    r = m

if check(r):
  ans = r
elif check(l):
  ans = l
else:
  ans = -1 # решения нет
# Функция check() возвращает 
# сначала False, потом True
# Необходимо найти 
# первый check() == True

l = 0
r = ??? # определяется из условия
while l + 1 < r:
  m = (l + r) // 2
  if not check(m):
    l = m
  else:
    r = m

if check(l):
  ans = l
elif check(r):
  ans = r
else:
  ans = -1 # решения нет

Значения границ (l и r) выбираются таким образом, что при значении l точно не подходит (не является решением), значение r точно подходит, хоть это значение и не является оптимальным.

Задача

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

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

Руководитель отдела качества очень хорошо к вам относится и написал для вас функцию isBadVersion(version), которая определяет является ли версия релиза плохой (возвращает True, если версия плохая, и False если хорошая).

Теперь вам необходимо реализовать функцию для поиска первой плохой версии. Вы должны как можно быстрее определить с какой версии пошел плохой релиз, поэтому количество использования функции isBadVersion(version) должно быть минимальным.

Ваша функция должна вернуть номер первого плохого релиза.