题目

给定 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。