Число единичек в двоичном представлении числа
Дано целочисленное число N без знака. Нужно подсчитать количество единичек в его двоичном представлении.
Например, число 11 в двоичном представлении выглядит 1011. Значит ответ будет 3.
Идея решения: если самый правый бит равен 1, то увеличить счётчик единичек. И в любом случае (0 или 1 справа) сдвинуть битовое представление на 1 позицию вправо, заменяя свободные биты слева нулями. Повторять до тех пор, пока результат сдвига не станет равен нулю.
Компилируемый код идеи решения:
int sum=0;
while(N!=0) {
if ((N&1)==1) sum++;
N = N >>> 1;
}
Проблема в том, что для больших чисел такой подсчёт может быть непозволительно длинным.
Ускорим алгоритм, находя сразу позицию p самого правого ненулевго бита и сдвигая число N на число позиций p:
int sum = 0; while (N!=0) { double position = 1 + Math.log(N & ~(N-1))/Math.log(2); if (position!=0) sum++; n >>>= (int)position; } return sum;
Поясним метод подсчёта position. Возьмём N=28.
Его двоичное представление = 11100. Это число X.
Двоичное представление 28-1=27 будет : 11011
Двоичное представление ~27 (инвертирование всех битов) : 00100 (с единичками впереди 11111111111111111111111111100100) Это число Y.
И подсчитав побитово X&Y мы получим : 100 в двоичной системе. Или 4 в десятичной.
Разложение 4 в двоичную систему происходит по фомуле 1*2^2 + 0*2^1 + 0*2^0.
Или 4 = 2^2. (Z)
Если прологарифмировать обе части по основанию 2, то равенство Z сохранится:
log2(4) = log2(2^2).
Пользуясь свойством стпени в логарифме: log2(2^2)=2*log2(2).
А log2(2)=1. Поэтому в итоге log2(4)=2. Это на 1 меньше, чем ожидаемоая позиция 3. Поэтому добаляем +1.
Проблема в том, что в библиотеке Java нет двоичного логарифма, а есть только натуральный.
Но у логарифма есть свойства log2(a) = logn(a)/logn(2).
Поэтому в итоге подсчёт значения position сводится к тому, что:
Например, число 11 в двоичном представлении выглядит 1011. Значит ответ будет 3.
Идея решения: если самый правый бит равен 1, то увеличить счётчик единичек. И в любом случае (0 или 1 справа) сдвинуть битовое представление на 1 позицию вправо, заменяя свободные биты слева нулями. Повторять до тех пор, пока результат сдвига не станет равен нулю.
Компилируемый код идеи решения:
int sum=0;
while(N!=0) {
if ((N&1)==1) sum++;
N = N >>> 1;
}
Проблема в том, что для больших чисел такой подсчёт может быть непозволительно длинным.
Ускорим алгоритм, находя сразу позицию p самого правого ненулевго бита и сдвигая число N на число позиций p:
int sum = 0; while (N!=0) { double position = 1 + Math.log(N & ~(N-1))/Math.log(2); if (position!=0) sum++; n >>>= (int)position; } return sum;
Поясним метод подсчёта position. Возьмём N=28.
Его двоичное представление = 11100. Это число X.
Двоичное представление 28-1=27 будет : 11011
Двоичное представление ~27 (инвертирование всех битов) : 00100 (с единичками впереди 11111111111111111111111111100100) Это число Y.
И подсчитав побитово X&Y мы получим : 100 в двоичной системе. Или 4 в десятичной.
Разложение 4 в двоичную систему происходит по фомуле 1*2^2 + 0*2^1 + 0*2^0.
Или 4 = 2^2. (Z)
Если прологарифмировать обе части по основанию 2, то равенство Z сохранится:
log2(4) = log2(2^2).
Пользуясь свойством стпени в логарифме: log2(2^2)=2*log2(2).
А log2(2)=1. Поэтому в итоге log2(4)=2. Это на 1 меньше, чем ожидаемоая позиция 3. Поэтому добаляем +1.
Проблема в том, что в библиотеке Java нет двоичного логарифма, а есть только натуральный.
Но у логарифма есть свойства log2(a) = logn(a)/logn(2).
Поэтому в итоге подсчёт значения position сводится к тому, что:
- мы подсчитываем число Q, которое начинается с самого правого бита исходного N.
- число Q мы логарифмируем, по основанию 2, чтобы подсчитать position.
- для того, чтобы получить основание 2, мы делаем Math.log(Q)/Math.log(2)+1.
- формула для получения двоичного представления, в котором включен только самый правый бит исходного числа N & ~(N-1)
- формула позиции самого правого бита: 1 + Math.log(N & ~(N-1))/Math.log(2)
Комментарии
Отправить комментарий