Leetcode #338 - Counting bits - Medium

Problem

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.

Example

For num = 5 you should return [0,1,1,2,1,2].

Follow up:

  • It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
  • Space complexity should be O(n).
  • Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.

Algorithm

整理一下题意:给定一个非负整数num,对于每个整数i(0<=i<=num),要求返回一个数组,其中第i项的值为i的二进制表示形式中1的个数。

看到题目后认定了动态规划的思路解决。最初的想法是,对于整数n,其二进制形式中,在第0位每减少1则表示n-1。但是考虑到n的二进制第0位不一定是1,也有可能是0,所以这一转换关系似乎并不能得到1的个数之间的关系。

继续考虑,如果除去第0位来看,只看其他位的情况是如何呢。例如,n=9的二进制表示是1001。除去第0位(1),其余位为100。如果知道了100只包含1个1,又确定了第0位是1,那么便可以知道1001一共有2个1了。1001的前三位的情况等价于100的总体情况,于是可以由100(n=4)时的数组值得到。而第0位的情况,只需要判断第0位是1还是0。由于第0位非0即1,前三位的情况直接加上第0位的值便是总体情况。于是可以得到状态转移方程,

s[n]=除去第0位的1的个数+第0位的值。

求第0位的值时,我原本的思路是通过移位得到,但实际操作时发现移位操作难以对移出位的值进行存储,所以放弃。于是从另一个角度考虑。如果第0位是1,说明n=2k+1恒成立,即n为奇数;如果第0位是0,则说明n位偶数。于是直接由(n%2==0)判断n的奇偶性即可知道第0位的值。代码如下

//奇偶判断版本,O(n),用时59ms
class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> bits(num+1,0);
        bits[0]=0;
        for(int i=1;i<num+1;i++){
            if(i%2==0)bits[i]=bits[i>>1];
            else bits[i]=bits[i>>1]+1;
        }
        return bits;
    }
};

完成题目后提交,通过。后来再查看DISCUSS时,发现判断第0位的值有一种更简便的方法,位运算。令n和1进行与操作,由与操作的特性可以直接得到第0位的值,即第0位等于 n&1 。

//与运算版本,O(n),用时86ms
class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> bits(num+1,0);
        bits[0]=0;
        for(int i=1;i<num+1;i++){
            bits[i]=bits[i>>1]+(i&1);
        }
        return bits;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值