比特位计数[动态规划 || bitCount计数]

前言

二进制计数可以直接基于分治去快速统计,如果是连续数的二进制计数,可以利用前面已经计算出的状态进行递推求解,即动态规划。

一、二进制计数

在这里插入图片描述

二、动态规划 & bitCount分治统计

1、bitCount分治统计

思想:每两位统一比特的个数,每四位统计比特的个数,依次类推,每十六位统计比特的个数。
bitCount分治统计源码解析,以及几处的细节优化。

func countBits(n int) []int {
    rs := make([]int,n + 1)
    for i := 1;i <= n;i++ {
        rs[i] = bitCount(i)
    }
    return rs
}
func bitCount(n int) int {
    // 两位二进制的规律
    n = n - ((n >> 1) & 0x55555555)
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
    // 最多八位二进制
    n = (n + (n >> 4)) & 0x0f0f0f0f
    // 最多16二进制,但即使是32位,8bit也足够表示了。
    n = n + (n >> 8)
    n = n + (n >> 16)

    return n & 0x3f
}

2、动态规划

对于连续求解数的二进制,可以利用前面已经统计的比特情况,来快速递推当前的比特数情况。
容易想到,dp[i] = dp[i >> 1] + (i & 1)

// 动态规划
// 末尾为1,直接dp[i] = dp[i >> 1] + 1;末尾为0,dp[i] = d[i >> 1]
func countBits(n int) []int {
    dp := make([]int,n + 1)
    for i := 1;i <= n;i++ {
        dp[i] = dp[i >> 1] + (i & 1)
    }
    return dp
}

总结

1)bitCount源码写的很好,好在分治思想,好在它挖掘了二进制而内的一些规律和限制,进行了多处优化,减少了多次位运算,提高性能。所以好在它的大思想+性能优化,好在它以提升性能为目的。
2)动态规划最重要的就是如何递推,有的简单的直接就看出来了,难的需要分析并分类合并递推公式。多练习才能做到一眼看出递推公式 + 分析分类合并递推公式的能力。

参考文献

[1] LeetCode 比特位计数
[2] bitCount源码解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值