或运算的最小翻转次数
描述:
给你三个正整数 a、b 和 c。
你可以对 a 和 b 的二进制表示进行位翻转操作,返回能够使按位或运算 a OR b == c 成立的最小翻转次数。
「位翻转操作」是指将一个数的二进制表示任何单个位上的 1 变成 0 或者 0 变成 1 。
示例 1:
输入:a = 2, b = 6, c = 5
输出:3
解释:翻转后 a = 1 , b = 4 , c = 5 使得 a OR b == c
示例 2:
输入:a = 4, b = 2, c = 7
输出:1
示例 3:
输入:a = 1, b = 2, c = 3
输出:0
提示:
1 <= a <= 10^9
1 <= b <= 10^9
1 <= c <= 10^9
分析
从a和b的 或运算 等于c,可以得出:
- c的二进制表示上的0,对应a和b上的该位的值一定都要转为0;
- c的二进制表示上的1,对应a和b上的该位的值至少要有一个转为1,即:若a和b对应该位上的值都为0,则只需翻转一次即可,否则无需翻转。
因此,最小翻转次数=(c的二进制表示为0的位对应a的该位上为1的个数)+(c的二进制表示为0的位对应b的该位上为1的个数)+(c的二进制表示为1的位对应a和b上该位都为0的个数)
而:
- c的二进制表示为0的位对应a的该位上为1的值 = c的非运算再跟a的与运算
- c的二进制表示为0的位对应b的该位上为1的值 = c的非运算再跟b的与运算
- c的二进制表示为1的位对应a为0的值 = c和a的与运算再跟c的异或运算
- c的二进制表示为1的位对应a和b上该位都为0的值 = 3得到的结果和b进行与运算再和3进行异或运算
解答:
class Solution {
/**
* @param Integer $a
* @param Integer $b
* @param Integer $c
* @return Integer
*/
function minFlips($a, $b, $c) {
$count1 = $this->_countNum(~$c & $a); // c的二进制表示为0的位对应a的该位上为1的个数
$count2 = $this->_countNum(~$c & $b); // c的二进制表示为0的位对应b的该位上为1的个数
$tmp = $c & $a ^ $c; // c的二进制表示为1的位对应a为0的值
$count3 = $this->_countNum($tmp & $b ^ $tmp); // c的二进制表示为1的位对应a和b上该位都为0的个数
return $count1 + $count2 + $count3;
}
/**
* 统计二进制数中1的个数
* @param byte $num [二进制数]
* @return Integer
*/
private function _countNum($num) {
$count = 0;
$flag = 1;
while ($flag != 0) {
if (($num & $flag) != 0) {
$count += 1;
}
$flag = $flag << 1;
}
return $count;
}
}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-flips-to-make-a-or-b-equal-to-c