整数比特翻转次数计算

 * 我们给定两个数字 A 和 B。我们的任务是计算将 A 转换为 B 所需翻转的位数。
 *
 * 解释:
 *
 * A  = 01010  B  = 10100
 * 如我们所见,A 中需要翻转的位是 01010。
 * 如果我们翻转这些位,我们得到 11110,这就是 B。
namespace bit_manipulation {
  
    namespace count_bits_flip {
   
        std::uint64_t countBitsFlip(
            std::int64_t A,
            std::int64_t B) {  // int64_t is preferred over int so that
            // no Overflow can be there.

            int count =
                0;  // "count" variable is used to count number of bits flip of the
            // number A to form B in binary representation of number 'n'
            A = A ^ B;
            while (A) {
                A = A & (A - 1);
                count++;
            }
            return count;
        }
    }  // namespace count_bits_flip
}  // namespace bit_manipulation

下面是对这段代码的详细解释:

名称空间(Namespace)

  • count_bits_flip:这是一个名称空间,用于组织代码,避免与其他代码的函数或变量名称冲突。

函数定义

  • countBitsFlip:这是一个函数,用于计算将整数 A 转换成整数 B 所需的比特翻转次数。

参数

  • A:这是一个 std::int64_t 类型的参数,表示要翻转的原始整数。

  • B:这也是一个 std::int64_t 类型的参数,表示目标整数。

返回值

  • 函数返回一个 std::uint64_t 类型的值,表示将 A 转换成 B 所需的比特翻转次数。

函数内部实现

  1. 异或操作

    • A = A ^ B;:这行代码对 AB 进行异或操作。异或操作会在 AB 的二进制表示中,将不同的位标记为 1,相同的位标记为 0。这样,异或后的结果中的每个 1 都表示需要翻转的位。

  2. 计数变量初始化

    • int count = 0;:这行代码初始化一个计数变量 count,用于统计需要翻转的位数。

  3. 循环统计 1 的个数

    • while (A):这个循环会一直执行,直到 A 变为 0。

    • A = A & (A - 1);:这行代码清除 A 的二进制表示中最右边的 1。具体来说,A - 1 会将最右边的 1 变为 0,并将右边的所有 0 变为 1。然后,对 AA - 1 进行按位与操作,就将最右边的 1 清除了 。                                                                            

    • count++;:每次循环,计数变量 count 增加 1,表示找到一个需要翻转的位。

  4. 返回结果

    • return count;:最后,函数返回计数变量 count,即所需的比特翻转次数。

整体思路

  • 该函数通过异或操作找出 AB 二进制表示中不同的位,然后统计这些不同位的个数,从而得到所需的比特翻转次数。

  • 使用 std::int64_t 类型是为了确保函数可以处理较大的整数范围,避免整数溢出问题。

这个方法的优点是高效且简洁,利用位运算的特性来快速统计所需的翻转次数,而不需要逐位检查。

下面通过举例来详细解释这句代码 A = A & (A - 1) 是如何清除 A 的二进制表示中最右边的 1 的。

假设 A = 6

二进制表示为 110

  1. A - 1

    • A 减去 1,即 6 - 1 = 5

    • 5 的二进制表示为 101

  2. A & (A - 1)

    • AA - 1 进行按位与操作。

    • 按位与操作的规则是:只有当两个位都为 1 时,结果位才是 1,否则为 0。

    • 对于 A = 6(二进制 110)和 A - 1 = 5(二进制 101),按位与操作的结果为 100(十进制的 4)。

通过这个操作,最右边的 1(即第二位的 1)被清除,变成了 0。

为什么这个操作有效?

  • A - 1 的原理

    • 当你对一个二进制数减去 1 时,它会将最右边的 1 变为 0,并将其右边的所有 0 变为 1。

    • 例如:

      • 如果 A1000(8),那么 A - 10111(7)。

      • 如果 A1010(10),那么 A - 11001(9)。

      • 如果 A1111(15),那么 A - 11110(14)。

  • 按位与操作的作用

    • 当我们将 AA - 1 进行按位与操作时,最右边的 1 会被清除,因为 A - 1 中的这个位置是 0,而其他位置保持不变。

    • 这个操作实际上是从右到左找到第一个 1,并将其变为 0,同时将其右边的所有位变为 1,然后按位与操作将这些右边的 1 变为 0。

表格
A二进制表示(A)A - 1二进制表示(A - 1)A & (A - 1)
61105101100
51014100100
71116110110
81000701110000
91001810001000
101010910011000

通过这些例子,可以看到每次执行 A & (A - 1) 操作后,最右边的 1 都会被清除。

这个操作非常高效,因为它避免了逐位检查,而是直接定位到最右边的 1 并清除它。这种方法在统计二进制数中 1 的个数或者类似的位操作场景中非常有用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值