Эта проблема может быть легко и эффективно решена с помощью двоичного поиска (который выполняется в O (log n), быстрее, чем линейный поиск, который является O (n)).Основная идея заключается в том, что если и только если все числа присутствуют до определенного индекса, то list [index] = index + 1 (например, list [0] = 1, list [1] = 2 и т. Д.).Это свойство может использоваться для определения того, находится ли наименьшее пропущенное число до или после определенного элемента списка, что позволяет выполнять двоичный поиск.
Реализация проста (я не знаю php, так что вот псевдокод)
lower_bound = 0
upper_bound = length(list) - 1
index = floor((lower_bound + upper_bound) / 2)
while (lower_bound != upper_bound)
if(list[index] = index + 1) // missing number is after index
lower_bound = index + 1
index = floor((lower_bound + upper_bound) / 2)
else // missing number is at or before index
upper_bound = index
index = floor((lower_bound + upper_bound) / 2)
missing_number = upper_bound + 1 // add 1 because upper_bound is the index
И missing_number
будет наименьшим пропущенным числом, или если пропущенных чисел нетбудет length(list) + 1
.
или с использованием рекурсии, которая, как я слышал, менее эффективна
first_missing_number(list, lower_bound, upper_bound) {
if(lower_bound = upper_bound) // found the first missing number
return upper_bound + 1 // add 1 because upper_bound is the index
index = floor((lower_bound + upper_bound) / 2)
if (list[index] = index + 1) // missing number is after index
first_missing_number(list, index + 1, upper_bound)
else // missing number is at or before index
first_missing_number(list, lower_bound, index)
}
В этом случае first_missing_number(list, 0, length(list) - 1)
вернет первый номер, отсутствующий в списке.Если пропущенные цифры отсутствуют, возвращается length(list) + 1
.
Надеюсь, это поможет!
upd: php version
function first_free($list) {
$lwr = 0;
$upr = count($list);
while ($lwr < $upr) {
$m = ($lwr + $upr) >> 1;
if($list[$m] == $m + 1)
$lwr = $m + 1;
else
$upr = $m;
}
return $upr + 1;
}