leetcode 338. 比特位计数

题目:

https://leetcode-cn.com/problems/counting-bits/

题解一:

将 num 转为2进制数,然后再求 "1" 的个数。

    public int[] countBits(int num) {
        int[] resultArr = new int[num + 1];
        for (int i = 0; i <= num; i++) {
            resultArr[i] = Integer.bitCount(i);
        }

        return resultArr;
    }

题解二:

如下表,我们先将十进制和二进制写出来仔细观察。

 

十进制二进制count("1")
000
111
21 01
3 1  12
41  0  01
51  0  12
61  1  02
71  1  13
81 0 0 01

 

规律:

  1. 如果 num 为 2 的整数次幂,那么 num 的二进制数中 1 的个数一定为 1,例: 2(10)、4(100)、8(1000)。
  2. num 数值上可以拆分成 2^n + j(2^n 为不超过 num 的最大值)。

由此可得dp方程:dp(num) = dp(2^n) + dp(j) = dp(j) + 1

举例:

dp(1) = dp(0) + 1 = 1;

dp(2) = 1;

dp(3) = dp(2) + dp(1) = 1 + 1 = 2;

dp(4) = 1;

dp(5) = dp(4) + dp(1) = 1 + 1 = 2;

dp(6) = dp(4) + dp(2) = 1 + 1 = 2;

所以这个题的关键在于如何求出不大于 num 的最大值 x 并且x 为 2 的整数次幂。我们可以使用与运算,如果正整数 x 是 2 的整数次幂,那么 x 的二进制中最高位一定是 1,其余都是0,因此 x&(x-1) = 0。由此可见,当且仅当 x&(x-1) = 0 时,x 才是 2 的整数次幂

    public int[] countBits(int num) {
        int[] resultArr = new int[num + 1];

        int temp = 1;
        for (int i = 1; i <= num; i++) {
            if ((i & (i-1)) == 0) {
                temp = i;
            }

            resultArr[i] = resultArr[i-temp] + 1;
        }

        return resultArr;
    }

时间复杂度:O(num) 。每个数都只需要 O(1) 的时间计算出其比特位计数。

 

题解三:

对于所有的十进制数,我们可以分为两类:

1.奇数。奇数的二进制低位肯定为 1,并且一定比前面一个偶数多一个 1,因为多的就是当前低位的 1。

2.偶数。偶数的二进制低位肯定为 0,并且二进制中 1 的个数与当前数除以 2 之后的个数一样多,因为当前数除以 2,等效于二进制数向右移一位,刚好把最低位的 0 移除掉,所以 1 的个数是一样的。

    public int[] countBits(int num) {
        int[] resultArr = new int[num + 1];

        for (int i = 1; i <= num; i++) {
            if (i % 2 == 0) {
                resultArr[i] = resultArr[i/2];
            } else {
                resultArr[i] = resultArr[i-1] + 1;
            }

        }

        return resultArr;
    }

 我们可以发现其实奇数也可以表示为向右移 1 位并加上 1(因为奇数向右移一位就把低位的 1 移出去了,所以需要加上 1),所以我们可以用位运算将代码简写:

    public int[] countBits(int num) {
        int[] resultArr = new int[num + 1];

        for (int i = 1; i <= num; i++) {
            resultArr[i] = resultArr[i>>1] + (i&1);
        }

        return resultArr;
    }

时间复杂度:O(num) 。每个数都只需要 O(1) 的时间计算出其比特位计数。

 

本题的解法有很多,位运算、动态规划等,虽然不是很难但是却很有意思。特别是位运算的解法,很巧妙,代码也非常简洁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值