LeetCode-338. Counting Bits

Description

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

1.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?
2.Space complexity should be O(n).
3.Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.

Solution 1(C++)

class Solution{
public:
    vector<int> countBits(int num){
        vector<int> res(num+1, 0);
        for(int i=0; i<=num; i++){
            bitset<32> b(i);
            res[i] = b.count();
        }
        return res;
    }
};

Solution 2(C++)

class Solution{
public:
    inline bool ispowerof2(int n){
        return (n & (n-1)) ==0;
    }

    vector<int> countBits(int num){
        vector<int> dp(num+1);
        dp[0] = 0;

        if(num >= 1) dp[1] = 1;

        int curr = 2;
        int neatest = 2;
        while(curr <= num){
            nearest = ispowerof2(curr) > curr : nearest;
            dp[curr] = 1 + dp[curr-nearest];
            curr++;
        }

        return dp;
    }
};

Solution 3(C++)

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

Solution 4(C++)

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

算法分析

解法一

解法一使用了bitset这个数据容器,具体可以参考:

并不是十分取巧的方法,但是比较容易想出来。

解法二

解法二、解法三、解法四都是基于一点:观察如下数字:

    ^^^^
0 :  0000 -->0
1 :  0001 -->1
--------------------------
2 :  0010 -->1
3 :  0011 -->2
--------------------------
4 :  0100 -->1
5 :  0101 -->2
6 :  0110 -->2
7 :  0111 -->3
--------------------------
8 :  1000 -->1
9 :  1001 -->2
10:  1010 -->2
11:  1011 -->3
12:  1100 -->2
13:  1101 -->3
14:  1110 -->3
15:  1111 -->4
--------------------------
    ^^^^

罗列了这么多数字,可以根据横线:”———”的划分,发现0、·与1、2最低为对应相同,但是高一位前二者为0,后二者为1。同样·0、1、2、3与4、5、6、7只有最高位对应不同,前四者均为0,后四者均为1。后面的就不一一赘述了。所以假如说我要求某一个数的二进制的1的个数,可以转换为对应的一个数的二进制的1的个数加1。这个对应的数该怎么求?就是解法二、三、四要解决的问题。

解法二的做法是,用curr表示要求的数,而nearest表示离他最近的转换的分界线,也就是我在表格中横线:”———”的划分下一个数:是2的幂次数。比如,要求10,那么根据表格,可以很轻松的找到,10就是2的二进制的1个数,再加上1。而10-8=2。所以解法二中有一句:

nearest = ispowerof2(curr) ? curr  : nearest; 

就是如果curr是新的2的幂次数,那么就要更新nearest。那么状态转移方程也可求得:dp[curr] = 1 + dp[curr-nearest];

解法三

根据进一步的观察,可以换个角度来看,如果一个dp[i] = n,那么dp[i*2] = n,肯定成立,相当于将n左移一位。那么不难的到新的状态转移方程:dp[i] = dp[i/2] + i%2。

解法四

根据上面的讨论,由于0~n中的数字可以按照最高位数字不同进行转换。所以,只要把二进制最高位数字去掉,那么就可以直接找到对应的数字。所以可得到状态转移方程:dp[i] = dp[i&(i-1)] + 1。类似的题目还可以参考:

程序分析

略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值