Все темы
132

Тридцать два переключателя в одном числе

Tier 1Закрыто

Где применяется

1. Задача

Дальше в курсе понадобятся два низкоуровневых инструмента: работа с отдельными битами числа и немного теории чисел. Бит это одна двоичная цифра, 0 или 1.

У пользователя есть права: чтение, запись, удаление, администрирование и ещё десяток. Самый очевидный способ их хранить: по одному значению true/false на каждое право, в маленьком объекте или массиве. Это работает. Но теперь у каждого пользователя целый набор true/false, и проверка «может ли он писать?» каждый раз лезет в этот набор.

Можно хранить плотнее. Целое число записано в памяти как ряд из 32 битов, и каждый бит уже сам по себе переключатель «да/нет». Упакуй все права в одно число. Тогда в базе это одно поле, передаёшь ты одно значение, а любой переключатель меняется одной операцией.

Для этого нужно уметь читать и менять один бит, не задевая остальные.

Этот шаг из платной части

Бесплатные шаги в начале курса (их 33) открыты всем: урок, задача и тесты. Этот шаг открывается с полным доступом. Начни с бесплатного аккаунта и бесплатных шагов.

Завести бесплатный аккаунтПосмотреть, что входит
Поиск числа без пары через XOR
findUnique([5, 3, 5, 6, 3])
nums
5
3
5
6
3
биты (столбец = сколько стоит бит)
8421
acc0000
acc = 0

Каждое число встречается дважды, кроме одного. acc начинается с 0, а a XOR b переключает биты a там, где у b стоит 1.

Гонка скорости
Подсчёт единичных битов одного и того же 32-битного числа: проверка всех 32 или сброс одной единицы за шаг

Столбики: 32 бита числа, старший слева, высокий столбик означает 1. Проверка каждого бита их только читает; приём Кернигана сбрасывает каждую посчитанную единицу, поэтому его столбики в конце обнулены.

Одна операция: один шаг цикла: проверка одного бита или сброс одного бита. За каждый кадр все дорожки делают одинаковое число операций, поэтому медленная отстаёт.

Проверка каждого бита O(n)
операций: 0
Приём Кернигана O(k)
операций: 0

 

А если чисел больше

Операции для n чисел и примерное время при 100 миллионах простых операций в секунду. Это оценка по тому же счёту, а не замер.

n = 1 000
Проверка каждого бита1 тыс. · меньше 1 мс
Приём Кернигана250 · меньше 1 мс
n = 100 000
Проверка каждого бита100 тыс. · 1 мс
Приём Кернигана25 тыс. · меньше 1 мс
n = 10 000 000
Проверка каждого бита10 млн · 100 мс
Приём Кернигана2,5 млн · 25 мс

Как узнать

Битовые манипуляции (Bit manipulation)

Эти слова в условии значат этот паттерн

  • найти единственное или уникальное число через XOR
  • установить, снять, переключить или проверить бит
  • упаковать много флагов да/нет в одно целое число
  • подсчёт установленных битов или проверка степени двойки

Похоже, но не то

Одна операция стоит O(1) на 32-битном значении. Проход по битам это O(32), то есть константа.

На LeetCode

Задачи, где читают, ставят или считают отдельные биты числа, например число единичных битов, сравнение двух чисел бит за битом или разворот битов. Маска 1 << i с AND, OR и NOT работает с одним битом за раз.

Мы используем необходимые куки для работы сайта (вход и язык). Если ты согласишься, мы также загрузим Google Analytics, чтобы видеть, какие страницы читают, и Google reCAPTCHA для защиты форм обратной связи и сообщений об ошибке от спама. Политика конфиденциальности