Это замечательная проблема для рекурсивного алгоритма.
Если длина двоичного представления равна 0, вы уже можете сказать ответ.Или, если длина 0 не разрешена, то если длина равна 1, вы сообщаете ответ в зависимости от того, равен ли этот бит 0 или 1.
Если длина больше 1:
- Если первый бит равен 0, ответ такой же, как и без этого 0 бита.Удалите его и вызовите рекурсивно, чтобы получить ответ.
- Если первый бит равен 1, разделите его на три подзадачи и найдите количество шагов для каждого:
- Создайте ситуацию, в которой вам разрешено изменятьот 1 до 0. Это означает, что за ним следует 1, а затем все 0.Напишите рекурсивный вспомогательный алгоритм для этого.Это будет очень похоже на основной алгоритм, и, вероятно, они могут разделить некоторую логику.
- Отразить 1 к 0 (1 шаг)
- Преобразовать оставшиеся биты в 0. Ещерекурсивный вызов.
Алгоритм может занять много времени.Это фактически подсчет шагов, поэтому требуется время, пропорциональное количеству шагов, которое, я думаю, примерно пропорционально вводимому числу.Ваш метод принимает аргумент long
, но с моим алгоритмом для больших значений long
он может не завершиться в течение срока службы компьютера, на котором он работает.Также количество шагов может превысить int
и даже long
(если входное значение является отрицательным long
).
Счастливое кодирование.Если бы это был я, я бы на самом деле запрограммировал и запустил его, чтобы убедиться, что все правильно понял.
Быстрый путь
Следующее решение не требует рекурсии и выполняется в постоянном времени.Я не могу правильно объяснить, как это работает, что является серьезной проблемой, если мы хотим использовать это для чего-то.Я играл с некоторыми примерами, видел шаблон и обобщал его.ИМХО, в отличие от этого, прелесть рекурсивного решения, описанного выше, состоит в том, что его легко понять (если вы понимаете рекурсию).
Пример: ввод 8 или 1000
двоичный файл.Результат 15 или 1111
двоичный.Шаблон таков: каждый бит результата - это XOR предыдущего бита результата и бит в той же позиции на входе.Таким образом, из 1000
просто скопируйте передний бит 1. Следующий бит равен 1 XOR 0 = 1, где 1 - это передний бит результата, а 0 - из входа.Оставшиеся два бита рассчитываются одинаково.
Более длинный пример, чтобы вы могли проверить, поняли ли вы:
Input: 115 = 1110011
Result: 1011101 = 93
Или в коде:
static BigInteger calculateStepsRequired(long number) {
// Take sign bit
int bit = number < 0 ? 1 : 0;
BigInteger result = BigInteger.valueOf(bit);
for (int i = 0; i < 63; i++) {
number = number << 1;
int sign = number < 0 ? 1 : 0;
bit = (bit + sign) % 2;
result = result.shiftLeft(1).add(BigInteger.valueOf(bit));
}
return result;
}
IЯ проверил этот метод по сравнению с моей собственной реализацией первого вышеупомянутого алгоритма, используя различные входные данные до 100 000 000, и они всегда соглашаются, поэтому я считаю, что быстрый метод также является правильным.