Вы можете решить исходную проблему в O (n), просто выполняя линейный обход массива, пока не найдете число, которое не соответствует ожидаемому значению, например, так (да, я знаю, что использую массив целых чисел, чтобы приблизить массив битов, но концепция та же самая):
int[] bits = {1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0};
int bitIndex = 0;
for (int num = 1; num < Integer.MAX_VALUE; num++) {
int numBits = (int) (Math.log(num) / Math.log(2)) + 1;
int nextNum = 0;
for (int index = 0; index < numBits; index++) {
nextNum = (nextNum << 1) | bits[bitIndex + index];
}
if (nextNum != num) {
System.out.println("Missing number: expected=" + num + ", actual=" + nextNum);
break;
}
bitIndex += numBits;
}
Если вы хотите напечатать все числа, которых нет в массиве, сохраняя время выполнения O (n), просто замените break;
на num = nextNum;
, чтобы продолжить проверку следующего номера.
Хотя есть некоторые потенциальные проблемы с этим подходом. Если пропущено несколько последовательных номеров, все ставки отключены. Кроме того, если число битов в num + 1
больше, чем число битов в num
, а num
отсутствует в массиве битов, то индекс битов будет не совпадать с данными.
Конечно, если допускается пропуск нескольких чисел, тогда проблема не решаема. Рассмотрим для примера:
{1,1,1,1,1,1,1}
В этом случае так же верно говорить, что у меня есть номера 1, 3 и 15, так же, как и то, что у меня есть только 127 или что у меня есть 7 и 15. Когда разрешено пропускать несколько последовательных значений, способ разбора битов по существу становится произвольным.
Так что, возможно, один из способов ответить на второй вопрос - это прочитать все биты в одно большое целое число и сказать: «у вас [очень большое число] и все числа до того, как оно пропущено». Тогда вы дали правильный ответ за O (n) раз.