5分钟学会微算法——Brian Kernighan 算法

Brian Kernighan 算法是一种高效计算二进制数中 1 的个数 (即 "汉明重量 / Hamming Weight")的经典算法,由计算机科学家 Brian Kernighan(C 语言设计者之一)提出。其核心优势是循环次数仅等于二进制中 1 的个数,比 "逐位遍历所有二进制位" 的暴力法更高效。

算法核心原理

Brian Kernighan 算法的核心依赖一个关键的位运算性质:对对于任意整数 x,令 x=x & (x−1),该运算将 x 的二进制表示的最后一个 1 变成 0,并保持其他位不变。

为什么 n & (n - 1) 能消除最右边的 1?

从二进制减法的逻辑可解释:

  1. n 的二进制末尾是 k 个 0(例如 n = 12,二进制为 1100,末尾 2 个 0):
    • n - 1 会将末尾的 k 个 0 全部变为 1,且将最右边的那个 1 变为 0(例如 12 - 1 = 11,二进制为 10111011 & 1100 = 1000)。
  2. n 的二进制末尾是 1(例如 n = 13,二进制为 1101):
    • n - 1 直接将末尾的 1 变为 0(例如 13 - 1 = 12,二进制为 1100,1100 & 1101 = 1100)。

此时对 nn - 1 做 "按位与(&)" 运算,由于最右边的 1 已被 n - 1 翻转为 0,且其右侧的位全为 1(与 n 的右侧 0 对应),最终结果会精准消除 n 最右边的 1。

示例 :以 n = 13(二进制 1101)为例

  • 第 1 次:n = 13 (1101)n-1 = 12 (1100)n & (n-1) = 12 (1100) → 消除最右边的 1(末尾的 1),计数 + 1。
  • 第 2 次:n = 12 (1100)n-1 = 11 (1011)n & (n-1) = 8 (1000) → 消除最右边的 1(第 3 位的 1),计数 + 1。
  • 第 3 次:n = 8 (1000)n-1 = 7 (0111)n & (n-1) = 0 (0000) → 消除最右边的 1(第 4 位的 1),计数 + 1。
  • 此时 n = 0,循环结束,最终计数为 3(13 的二进制确实有 3 个 1)。

算法流程

  1. 初始化计数 :设置一个计数器 count = 0,用于记录 1 的个数。

  2. 循环消除 1 :只要 n != 0,就执行以下操作:

    • 计算 n = n & (n - 1),消除 n 最右边的 1。
    • 计数器 count += 1(每消除一个 1,计数加 1)。
  3. 返回结果 :当 n 变为 0 时,count 即为二进制中 1 的总个数。

    cpp 复制代码
    int countOneBits(int n) {
        int count = 0;
        while (n) {          // 当 n 不为 0 时循环
            n &= (n - 1);    // 消除最右边的 1
            count++;         // 计数加 1
        }
        return count;
    }

简单推理

对于(n = 1,2,3,......)都是最高位是1,其余位都是0的,所以如果 i & (i - 1) = 0,则i是2的整数次幂。

方法开拓

如果想要线性的求n个数的二进制1的个数,可以采用动态规划的方法。

比如对于二进制数1010,可以看做1010 = 1000 + 10,我设x=1010,y=1000,z=10,其中z=x-y。

而且不难发现z的二进制中1的个数=y的二进制中1的个数+z的二进制中1的个数,而y是2的n次幂的类型,所有bit1[x] = bit1[x - y] + 1 =bit1[z] + 1;//这里的bit1代表二进制中1的个数。

leetcode例题

cpp 复制代码
class Solution {
public:
    vector<int> countBits(int n) {
        int level = 0;
        vector<int> ans(n+1);
        ans[0] = 0;
        for(int i = 1;i <= n;++i){
            if(!(i & (i - 1))){
                level = i;
            }
            ans[i] = ans[i - level] + 1;
        }
        return ans;
    }
};
相关推荐
业精于勤的牙1 小时前
三角形最小路径和(二)
算法
风筝在晴天搁浅1 小时前
hot100 239.滑动窗口最大值
数据结构·算法·leetcode
夏乌_Wx2 小时前
练题100天——DAY31:相对名次+数组拆分+重塑矩阵
数据结构·算法
LYFlied2 小时前
【算法解题模板】-解二叉树相关算法题的技巧
前端·数据结构·算法·leetcode
Ven%2 小时前
【AI大模型算法工程师面试题解析与技术思考】
人工智能·python·算法
天勤量化大唯粉2 小时前
枢轴点反转策略在铜期货中的量化应用指南(附天勤量化代码)
ide·python·算法·机器学习·github·开源软件·程序员创富
爱学习的小仙女!2 小时前
算法效率的度量 时间复杂度 空间复杂度
数据结构·算法
AndrewHZ2 小时前
【复杂网络分析】什么是图神经网络?
人工智能·深度学习·神经网络·算法·图神经网络·复杂网络
Swizard3 小时前
拒绝“狗熊掰棒子”!用 EWC (Elastic Weight Consolidation) 彻底终结 AI 的灾难性遗忘
python·算法·ai·训练
fab 在逃TDPIE3 小时前
Sentaurus TCAD 仿真教程(十)
算法