[Week 13] LeetCode 338. Counting Bits

15 篇文章 0 订阅
13 篇文章 0 订阅

LeetCode 338. 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

Example 1:

Input: 2
Output: [0,1,1]

Example 2:

Input: 5
Output: [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

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

题解

简单粗暴的咱不讲,不如根据题目的提示,探究一下这些二进制数字的规律吧:

val      bin      1s     index
-------------------------------
 0        0        0       -
-------------------------------
 1        1        1      2^0
-------------------------------
 2       10        1      2^1
 3       11        2
-------------------------------
 4      100        1      2^2
 5      101        2
 6      110        2
 7      111        3
-------------------------------
 8     1000        1      2^3
 9     1001        2
10     1010        2
11     1011        3
12     1100        2
13     1101        3
14     1110        3
15     1111        4
-------------------------------
...

根据提示2,我们可以将数字按[2,3]、[4,7]、[8,15]这样分组,其依据为二进制表示所需最少位数,因为0和1比较特别,所以我们可以通过硬编码的方法来写入返回数组。观察每个分组我们可以发现,某分组结果的前一半跟上一组完全相同,而后一半由前一半加1可得,这里我们不去探究其原理,我们只将它作为一个数字游戏:已知result[0] = 0result[1] = 1 ,利用前面的规则依次求result[2:3]result[4:7] … 即每次求解一个分组,第k个分组(从1开始)的大小为2^(k+1) - 2^k,开始下标为2^k,每次通过将上一个分组复制到本分组的前半部分,然后将前半部分分别加1后复制给后半部分,只不过给定 num 不一定是2的幂,所以需要判断一下是否超过num,代码如下。

Code

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> result(num + 1, 0);
        if (num > 0) result[1] = 1;
        for (int k = 1; pow(2, k) <= num; ++k) {
            int mid = (int)(pow(2, k + 1) - pow(2, k)) / 2;
            for (int i = pow(2, k); i < pow(2, k) + mid; ++i) {
                if (i > num) break;
                result[i] = result[i - mid];
                if (i + mid <= num) result[i + mid] = result[i] + 1;
            }
        }
        return result;
    }
};

复杂度

复杂度是一目了然的,空间复杂度为O(n),因为我们只在返回数组上操作;时间复杂度也是O(n),因为我们从头到尾只是一次给数组每个位置赋值,且每个赋值操作时间复杂度都为 O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值