剑指offer_3_前n个数字二进制形式中1的个数(java)

简介: 剑指offer_3_前n个数字二进制形式中1的个数(java)

 一、问题描述

输入一个非负数n,请计算0到n之间每个数字的二进制形式中1的个数,并输出一个数组。例如,输入的n为4,由于0、1、2、3、4的二进制形式中1的个数分别为0、1、1、2、1,因此输出数组[0,1,1,2,1]。

二、问题分析

每次用“i&(i-1)”将整数i的最右边的1变成0。整数i减去1,那么它最右边的1变成0。如果它的右边还有0,则右边所有的0都变成1,而其左边所有位都保持不变。下面对i和i-1进行位与运算,相当于将其最右边的1变成0。以二进制的1100为例,它减去1的结果是1011。1100和1011的位与运算的结果正好是1000。二进制的1100最右边的1变为0,结果刚好就是1000。

关键处理好进位;

三、代码实现

/**
     * 每次用“i&(i-1)”将整数i的最右边的1变成0。
     * 整数i减去1,那么它最右边的1变成0。如果它的右边还有0,则右边所有的0都变成1,而其左边所有位都保持不变。
     * 下面对i和i-1进行位与运算,相当于将其最右边的1变成0。
     * 以二进制的1100为例,它减去1的结果是1011。1100和1011的位与运算的结果正好是1000。
     * 二进制的1100最右边的1变为0,结果刚好就是1000。
     *
     * @param num
     * @return
     */
    public static int[] countBIt1(int num) {
        int[] res = new int[num + 1];
        for (int i = 1; i < num; i++) {
            int j = i;
            while (j != 0) {
                res[i]++;
                j = j & (j - 1);
            }
        }
 
        return res;
    }
 
    /**
     * “i&(i-1)”将i的二进制形式中最右边的1变成0,
     * 也就是说,整数i的二进制形式中1的个数比“i&(i-1)”的二进制形式中1的个数多1
     *
     * @param num
     * @return
     */
    public static int[] countBIt2(int num) {
        int[] res = new int[num + 1];
        for (int i = 1; i < num; i++) {
            res[i] = res[i & (i - 1)] + 1;
        }
 
        return res;
    }
 
    /**
     * 如果正整数i是一个偶数,那么i相当于将“i/2”左移一位的结果,
     * 因此偶数i和“i/2”的二进制形式中1的个数是相同的。
     * 如果i是奇数,那么i相当于将“i/2”左移一位之后再将最右边一位设为1的结果,
     * 因此奇数i的二进制形式中1的个数比“i/2”的1的个数多1。
     * 例如,整数3的二进制形式是11,有2个1。偶数6的二进制形式是110,有2个1。
     * 奇数7的二进制形式是111,有3个1。我们可以根据3的二进制形式中1的个数直接求出6和7的二进制形式中1的个数。
     *
     * @param num
     * @return
     */
    public static int[] countBIt3(int num) {
        int[] res = new int[num + 1];
        for (int i = 1; i < num; i++) {
            res[i] = res[i >> 1] + (i & 1);
        }
 
        return res;
    }

四、测试

System.out.println(Arrays.toString(countBIt1(4))); //[0, 1, 1, 2, 0]
System.out.println(Arrays.toString(countBIt2(4))); //[0, 1, 1, 2, 0]
System.out.println(Arrays.toString(countBIt3(4))); //[0, 1, 1, 2, 0]

相关文章
|
1月前
|
Java Go 开发工具
【Java】(2)Java数据类型阐述、基本数据类型的占用和范围、二进制的讲述
数据的一种表示形式。十进制表示满十进一原则。二进制表示满二进一原则。例如:十进制例如:二进制计算机在任何情况下都只能识别二进制。
117 1
剑指offer_2_二进制加法(java)
剑指offer_2_二进制加法(java)
112 0
剑指offer_1_整数除法(java)
剑指offer_1_整数除法(java)
161 0
|
算法 Java Go
【经典算法】LeetCode 67. 二进制求和(Java/C/Python3/Golang实现含注释说明,Easy)
【经典算法】LeetCode 67. 二进制求和(Java/C/Python3/Golang实现含注释说明,Easy)
481 2
|
存储 安全 Java
剑指offer全集系列Java版本(2)
剑指offer全集系列Java版本(2)
134 0
|
存储 Java
剑指offer全集系列Java版本(1)
剑指offer全集系列Java版本(1)
110 0
Java中整数(负数)的二进制表示
Java中整数(负数)的二进制表示
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
143 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
161 1
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案