LeetCode之338—-Counting Bits

最近上算法课上的有点心塞,所以感觉应该刷刷题来见见世面了,所以选择了LeetCode来做一点题目。

LeetCode之338:

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.

题目大意:

给定数字num, 计算i在 0 <= i <= num 之间的所有数字二进制表示形式中1的数量,以数组的形式返回结果(时间复杂度要求在O(n),空间复杂度要求在O(n))


思路:

拿到题目自然而然能够想到第一个思路:可以通过位运算找出每一个数字中1的个数,然后存入一个vector中,但是这样做的话每个数字的循环次数最坏是32次,这样的话可能会超时,但是可以达到目的。在此基础上再加以改进可以得到第二个思路:每个数字转化为二进制之后都是在n – 1的基础之后上加1,所以可以让n & (n – 1)消去n中的1,直至所有的1消失。这样每个数字的移位次数只有1的个数次。虽然没有达到O(n)的时间复杂度,但是也接近了一些。抱着试试看的态度提交了一下。好吧。。。。。过了。


代码:

#include <iostream>
#include <cstdlib>
#include <vector>

class Solution {

public:
    std::vector<int> countBits(int num) {
        int count, tmp;
        for (int i = 0; i <= num; ++i) {
            for (count = 0, tmp = i; tmp; ++count) {
                tmp = tmp & (tmp - 1);
            }
            v.push_back(count);
        }
        
        return v;
    }

private:
    std::vector<int> v;

};

虽然提交过了但是心里总有一些不安的感觉,因为题目要求是O(n)的复杂度,经过看提供的答案代码看到了一个很棒的解法:


代码:

vector<int> countBits(int num) {

    vector<int> rst(num + 1);

    rst[0] = 0;

    for (int i = 1; i <= num; i++) 

        rst[i] = rst[i >> 1] + (i & 1);

    return rst;
}

  这次是真的O(n)的时间复杂度,分析代码可以总结出原理:如果n是偶数则1的个数等于n/2的中1的个数,因为n是由n/2左移一位得到的,而左移不会增加1的个数,如果n是奇数则1的个数等于n/2中1的个数加一,因为n是由n/2左移一位加一。为了代码的简洁性就写成了如上形式。不得不说这个方法太巧了!良辰服辣~~

posted @ 2016-03-26 15:31  Jung_zhang  阅读(188)  评论(0编辑  收藏  举报