比特位计数

118 阅读1分钟

题目

动态规划

public class Main {
    public static void main(String[] args) {

        Main main = new Main();
        main.countBits(1);
    }

    public int[] countBits(int num) {
        if (num == 0) {
            return new int[]{0};
        }

        // 观察发现每个元素二进制1的个数会由之前的某个元素,通过首位添加1一个1得到
        // 具体由哪个元素和当前元素的大小, 以及和最接近当前元素的2^m次的值有关
        // 首先0, 1 两个数字是起始数字 dp[0] = 0; dp[1] = 1;
        // 例如2 >= 2^1 那么dp[2] = dp[2 - 2^1] + 1= dp[0] + 1
        //  2^2 > 3 >= 2^1 dp[3] = dp[3 - 2^1] + 1 = dp[1] + 1
        // 例如8 >= 2^3 那dp[8] = dp[8 - 2^3] + 1 = dp[0] + 1
        // 以此类推需要判断最接近当前元素的2^m次的值

        // 生成一个最大值小于num的 2^m的数组
        int [] support = new int[32];
        for (int i = 0;i < num; i ++) {
            int value = calculate(i + 1);
            support[i] = value;
            if (value > num) {
                break;
            }

        }

        int [] dp = new int[num + 1];
        dp[0] = 0;
        dp[1] = 1;
        int index = 0;
        int pre = support[index];
        int after = support[index + 1];
        for (int i = 2; i <= num; i ++) {
            if (i >= pre && i < after) {
                dp[i] = dp[i - pre] + 1;
            } else {
                dp[i] = dp[i - after] + 1;
                index = index + 1;
                pre = support[index];
                after = support[index + 1];
            }
        }
        return dp;
    }

    private int calculate(int n) {
        if (n == 0)
            return 1;
        return 2 * calculate(n - 1);
    }
}

基本思路

  1. 注意2^m次的求发, 注意求出多少2^m次的值就够用了, 不用多求

  2. 每次使用注意替换两个support的值就可以了