leetcode笔记:Counting Bits

一. 题目描述

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.

Hint:

You should make use of what you have produced already.
Divide the numbers in ranges like [2-3], [4-7], [8-15] and so on. And try to generate new range from previous.
Or does the odd/even status of the number help you in calculating the number of 1s?

二. 题目分析

题目大意是,给定一个非负整数num,对于每一个满足0 ≤ i ≤ num的数字i,计算这些数字的二进制表示中1的个数,并以数组vector的形式返回。

题目还给出了一系列提示:

很容易想到运行时间为:O(n*sizeof(integer)) 的解法。但你可以用线性时间:O(n)的一趟算法完成吗?空间复杂度应当为:O(n)

你可以像老板那样?不要使用任何内建函数(比如C++的__builtin_popcount)。

提示:

你应该利用已经得到的结果。

将数字拆分为诸如 [2-3], [4-7], [8-15] 之类的范围。并且尝试根据已经生成的范围产生新的范围。

也许数字的奇偶性可以帮助你计算1的个数?

从题目中给出的诸多提示,加上手写实例,容易发现一些规律,并得到多种方法,这里只列出两种位运算的解决方法。

方法一:

0   0000
1   0001
2   0010 // 左移一位,发现位数和(2/2 = 1)一致
3   0011 // 左移一位,发现位数和(2/2 = 1)一致,只是3为奇数,需要比1多1个1
4   0100
5   0101
6   0110
7   0111
8   1000 // 左移一位,发现位数和(8/2 = 4)一致
9   1001 // 左移一位,发现位数和(9/2 = 4)一致,只是9为奇数,需要比4多1个1
10  1010
11  1011
12  1100
13  1101
14  1110 // 左移一位,发现位数和(14/2 = 7)一致
15  1111 // 左移一位,发现位数和(15/2 = 7)一致,只是15为奇数,需要比7多1个1

根据以上实例,设F[n]表示正整数n的二进制个数,则可得到以下方程:

F[n] = F[n / 2] + F[n] & 1,根据这个方程,只需遍历一次0 ~ num的整数,即可得到各整数的二进制表示中含1的个数。

方法二:

0   0000
1   0001
2   0010
3   0011 // 对于非2的幂次数n,其二进制表示中1的个数比(n & (n - 1))多一个
4   0100
5   0101
6   0110
7   0111
8   1000 // 对于2的幂次数n,(n & (n - 1)) = 0,同样满足二进制表示中1的个数比(n & (n - 1))多一个
9   1001
10  1010
11  1011
12  1100
13  1101
14  1110
15  1111

该规律较难找出,可得到以下方程:F[n] = F[n & (n - 1)] + 1

三. 示例代码

// C++,方法一
class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> result;
        if (num < 0) return result;
        result.push_back(0);
        for (int i = 1; i <= num; ++i)
        {
            result.push_back(result[i >> 1] + (i & 1));
        }
        return result;
    }
};
# Python,方法一
class Solution(object):
    def countBits(self, num):
        """ :type num: int :rtpye: List[int] """
        result = [0]
        for i in range(1, num + 1):
            result += result[i >> 1] + (i & 1),
        return result
// C++,方法二
class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> result;
        if (num < 0) return result;
        result.push_back(0);
        for (int i = 1; i <= num; ++i)
        {
            result.push_back(result[i & (i - 1)] + 1);
        }
        return result;
    }
};
# Python,方法二
class Solution(object):
    def countBits(self, num):
        """ :type num: int :rtype: List[int] """
        result = [0]
        for i in range(1, num + 1):
            result += result[i & (i - 1)] + 1,
        return result

四. 小结

最近项目组中期检查,耗费了不少时间,算法也没之前写的多了,思想容易迟钝。

点赞