Минимальное количество переворотов, чтобы сделать A | B == C
Описание задачи #
Даны три целых положительных числа a, b и c.
Необходимо найти минимальное количество переворотов битов в a и b, чтобы результат операции a OR b (побитовая
операция ИЛИ) был равен c.
Операция переворота состоит из изменения любого отдельного бита с 1 на 0 или c 0 на 1 в его двоичном
представлении.
Ограничения #
- Значение каждого аргумента находится в диапазоне от 1 до 109
Примеры #
-
Входные данные:
a = 2, b = 6, c = 5Ответ:
3
В исходных числах нужно поменять три бита, подсвеченных красным.
-
Входные данные:
a = 4, b = 2, c = 7Ответ:
1
В исходных числах нужно поменять один бит, подсвеченный красным.
-
Входные данные:
a = 1, b = 2, c = 3Ответ:
0
В исходных числах ничего не нужно менять, так как условие уже выполняется.
Решение #
Чтобы решить задачу, нам необходимо представить числа a, b и c в двоичном виде и произвести их сравнение побитно.
Недостающие биты в числах мы заполняем ведущими нулями.
Если бит числа c равен 1, это означает, что в a и b как минимум один бит на этой же позиции должен быть
равен 1, чтобы условие a | b == c было истинным. Если же оба бита в a и b равны 0, то нам необходимо изменить
любой из битов на единицу.
Не важно какой именно бит, потому что это не меняет результат.
Если бит числа c равен 0, это означает, что биты и в числе a, и в числе b должны быть равны нулю, чтобы
условие a | b == c было истинным. В этом случае нам нужно изменять биты в a и b только в том случае, если они
равны 1.
Как получить двоичное представление числа?
На самом деле число не нужно переводить в двоичную систему счисления. Достаточно воспользоваться небольшим математическим хаком.
- Чтобы получить младший бит числа в двоичном представлении (крайний справа) необходимо взять остаток от деления числа
на 2. Это работает потому что у четных чисел младший бит всегда равен
0, а у нечетных —1. - Чтобы откинуть младший бит у числа достаточно разделить его на 2 без остатка. В таком случае мы получим новое число, которое в двоичном представлении равно предыдущему числу без младшего бита.
В итоге, нам необходимо иметь цикл, который проверяет младшие биты всех чисел на каждой итерации и увеличивает счетчик,
а по завершению итерации модифицирует исходные числа. Этот цикл работает до тех пор, пока все числа не станут равны 0.
Реализация #
-
package main func minFlips(a int, b int, c int) int { res := 0 for a > 0 || b > 0 || c > 0 { bitA := a % 2 bitB := b % 2 bitC := c % 2 a = a / 2 b = b / 2 c = c / 2 if bitA|bitB == bitC { // Условие задачи выполняется, значит биты на этой позиции менять не нужно continue } if bitC == 0 { res += bitA + bitB } else { res += 1 } } return res } -
export const minFlips = (a: number, b: number, c: number): number => { let res = 0; while (a > 0 || b > 0 || c > 0) { let bitA = a % 2; let bitB = b % 2; let bitC = c % 2; a = Math.floor(a / 2); b = Math.floor(b / 2); c = Math.floor(c / 2); if ((bitA | bitB) == bitC) { // Условие задачи выполняется, значит биты на этой позиции менять не нужно continue; } if (bitC == 0) { res += bitA + bitB; } else { res += 1; } } return res; };
Оценка сложности #
n - количество элементов в строке.
По времени
Сложность по времени O(n), так как мы гарантированно найдем ответ, перебрав полностью всю строку один раз.
По памяти
Сложность по памяти O(1).