Counting Bits


问题分析

1. 这题看上去是一道比较有意思的数论题,应该是要用到位运算,所以试着做了一下。

2. 给出一个整数num,要求统计0到这个整数num的二进制写法中1的个数。最容易的做法就是转换为二进制一位一位统计,这是题目中描述的O(n*sizeof(integer))的时间复杂度,又或者考虑将0到MAX_INT的1的个数前缀和存起来直接打表输出。但题目要求时间和空间都要是O(n)的级别,这两种方案显然都是不能通过的。

3. 尝试用找规律的方法做,考虑将[0, 2^(k+1)]划分为一个区间。

第一个区间 [0, 1]

第二个区间 [00, 01, 10, 11]

第三个区间 [000, 001, 010, 011, 100, 101, 110, 111]

...

也就是后一个区间是在前面全部区间的基础上全部加上前缀1,可以由此得到递推公式

ak 是从[0, 2^k - 1]中的1的个数

a1 = 1

a2 = a1 * 2 + 2 ^ 1

...

an = an-1 * 2 + 2 ^ (n - 1)

依据这个递推公式和规律可以很容易地算出num中二进制中1的个数。

4. 再考虑其实这个递推公式可以转化为更简单的形式

即如果k是奇数,则k中1的数量等于k / 2的1的数量加一,对应的是增加后缀1

如果k是偶数,则k中1的数量等于k / 2的1的数量,对应的是增加后缀0

5. 最后一个方法是我在网上看到的很漂亮的写法

指出 i 和 i & (i - 1)之间1的数量恰好差1,可以利用这个关系来求解

但是让我好奇的是为什么这个关系是成立的

考虑一个二进制串 [a b c d]

假设d为1,则i - 1为 [a b c 0]

i & (i - 1) = [a b c 0] 恰好差一个1

假设d为0,则i - 1为 [a b -c 1] (此时c为1)或 [a -b -c 1] (此时c为0 b为1)或 [-a -b -c 1] (此时c为0 b为0 a为1)

也就是i比(i - 1)恰好多从右边开始数起的第一个1

仔细想利用这个方法似乎可以快速判断右边开始的第一个1是在哪里,或者某个数是否是2的整数次幂。


题目代码

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> res(num + 1, 0);
        for (int i = 1; i <= num; ++i) {
            res[i] = res[i & (i - 1)] + 1;
        }
        return res;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值