或運算的最小翻轉次數
描述:
給你三個正整數 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