Бинарный поиск в интервале
Перейти к навигации
Перейти к поиску
В основной статье мы рассмотрели, как писать бинарный поиск до двух элементов и проверять их отдельно. Эту реализацию при желании можно оптимизировать.
Варианты задачи:
- Массив a[] отсортирован так, что функция f(a[i]) возвращает сначала true, затем false. Нужно найти последний элемент, для которого f(a[i]) == true;
- Массив a[] отсортирован так, что функция f(a[i]) возвращает сначала false, затем true. Нужно найти первый элемент, для которого f(a[i]) == true.
Правила:
- Поиск производится не в отрезке [l; r], а в интервале (l; r). Начальные значения: l = -1, r = size. Считаем, что начальный l даёт true, начальный r — false (или наоборот, в зависимости от варианта задачи);
- Поиск всегда осуществляется до двух элементов (while (l + 1 < r)). Между этими элементами будет проходить граница true и false (false и true);
- После проверки среднего элемента границы всегда смещаются только на середину (l = m или r = m, никаких плюс-минус единиц);
- Смещение границ должно происходить так, чтобы не потерять искомый элемент;
- Когда цикл завершится, если мы искали последний элемент, то нам нужен l, если первый — то r. Здесь нужно проверить, что l или r не равен -1 или size. В ряде случаев нужно проверить, что для выбранного элемента выполняется некоторое условие (например, мы искали первый элемент, равный x, а найдём первый элемент, больший или равный x, и равенство нужно проверить отдельно).
Первый вариант задачи:
// f() возвращает
// сначала true, потом false
// последний f() == true
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (f(a[m]))
l = m;
else
r = m;
}
if (l != -1)
return l;
return -1;
|
// сорт. по неубыванию
// последний элемент < x
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (a[m] < x)
l = m;
else
r = m;
}
if (l != -1)
return l;
return -1;
|
// сорт. по неубыванию
// последний элемент <= x
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (a[m] <= x)
l = m;
else
r = m;
}
if (l != -1)
return l;
return -1;
|
// сорт. по неубыванию
// последний элемент == x
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (a[m] <= x)
l = m;
else
r = m;
}
if (l != -1 && a[l] == x)
return l;
return -1;
|
Второй вариант задачи:
// f() возвращает
// сначала false, потом true
// первый f() == true
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (f(a[m]))
r = m;
else
l = m;
}
if (r != size)
return r;
return -1;
|
// сорт. по неубыванию
// первый элемент > x
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (a[m] > x)
r = m;
else
l = m;
}
if (r != size)
return r;
return -1;
|
// сорт. по неубыванию
// первый элемент >= x
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (a[m] >= x)
r = m;
else
l = m;
}
if (r != size)
return r;
return -1;
|
// сорт. по неубыванию
// первый элемент == x
int l = -1, r = size;
while (l + 1 < r) {
int m = l + (r - l) / 2;
if (a[m] >= x)
r = m;
else
l = m;
}
if (r != size && a[r] == x)
return r;
return -1;
|