题目
给定 a、b、c 求一个最小翻转次数,使得通过翻转 a、b 中的比特位,得到 a | b = c。
例如 a = 1, b = 1, c = 2 时,需要翻转3次:
a = 1 反转2次到 10; b=1 翻转1次到 0;最后 10 | 0 = 10 = c
解答
笨办法就是做循环;好办法是下面这样子:
#include <stdio.h>
#include <stdint.h>
#include <x86intrin.h>
int bit_flips(uint32_t a, uint32_t b, uint32_t c)
{
uint32_t mask = (a | b) ^ c;
uint32_t m32 = 0xffffffff;
uint32_t x = (a ^ b ) & mask; // 只需反转 a 或 b
uint32_t y = (a ^ b ^ m32) & mask; // a,b 位都要反转,所以下面 *2
int result = _mm_popcnt_u32(x) + _mm_popcnt_u32(y) * 2;
printf("%lu | %lu flips to %lu\nresult: %lu\n\n", a, b, c, result);
return result;
}
int main(int argc, const char *argv[])
{
bit_flips(1,1,1);
bit_flips(1,2,1);
bit_flips(1,1,3);
bit_flips(1,1,4);
bit_flips(16,0,0);
bit_flips(16,1,0);
return 0;
}
[xiaochu.yh ~/tools] $g++ test.cpp -march=native
[xiaochu.yh ~/tools] $./a.out
1 | 1 flips to 1
result: 0
1 | 2 flips to 1
result: 1
1 | 1 flips to 3
result: 2
1 | 1 flips to 4
result: 4
16 | 0 flips to 0
result: 1
16 | 1 flips to 0
result: 2
说明:
解题关键:_mm_popcnt_u32(n)
函数能以 O(1) 的方式计算出数字 n 中有多少个比特1。