剑指offer 面试题10 二进制中 1 的个数

剑指offer 面试题10 二进制中 1 的个数

题目:
请实现一个函数,输入一个整数,输出该整数二进制表示中 1 的个数。
例如把 9 表示成二进制是 1001, 有 2 位是 1。因此如果输入 9,该函数输出 2。

package algorithm.foroffer;

/**
 * Created by liyazhou on 2017/5/25.
 * 面试题10:二进制 1 的个数
 * 题目:
 *      请实现一个函数,输入一个整数,输出该整数二进制表示中 1 的个数。
 *      例如把 9 表示成二进制是 1001, 有 2 位是 1。因此如果输入 9,该函数输出 2。
 */
public class Test10 {

    /**
     * 思路:
     *      1. 使用Integer.toBinaryString(int number),将整数转换为二进制数组
     *      2. 统计字符串中 1 的个数
     * @param n 整数
     * @return 1 的个数
     */
    public static int numberOfOne(int n){
        String binString = Integer.toBinaryString(n);
        System.out.println(String.format("binString of %d, %s", n, binString));
        int counter = 0;
        for (int i = 0; i < binString.length(); i++)
            if (binString.charAt(i) == '1')
                counter ++;
        return counter;
    }

    /**
     * 思路:
     *      1. 将帧数转换为二进制字符串
     *      2. 统计字符串中 1 的个数
     * @param n 整数
     * @return 1 的个数
     */
    public static int numberOfOne2(int n){
        String binString = getBinString1(n);
        System.out.println(String.format("binString of %d, %s", n, binString));
        int counter = 0;
        for (int i = 0; i < binString.length(); i++)
            if (binString.charAt(i) == '1')
                counter ++;
        return counter;
    }

    /**
     * 将一个十进制整数转换为二进制字符串
     *
     * 在计算机中,为了方便计算(计算机中只有加法运算),所有数字都是用其补码表示的
     *
     * 原码、反码和补码详解:
     *  int类型的表示范围是 [-2^31, 2^31-1]
     *  1. 正整数,表示范围是 [1, 2^31-1]
     *      正整数的原码 = 反码 = 补码
     *
     *  2. 负整数(不能超出表示范围 [-2^31, -1])
     *      负整数的原码,求负整数绝对值的原码,并将(最左边、最高位)符号位设置为 1
     *      负整数的反码,在原码的基础上,符号位不变,其余取反
     *      负整数的补码,在其原码的基础上,符号位不变,其余取反,最后加 1(或者表述为,在负整数的反码基础上,加 1)
     *
     *      负整数的补码转化为反码,负整数的补码减 1
     *      负整数的反码转化为原码,符号位不变,其余取反
     *
     *  3. 零,表示 0
     *      和正整数一样,其原码 = 反码 = 补码,为 [0000 0000 0000 0000]
     *
     * 注意:
     *      8 位二进制整数的取值范围是 [1111 1111, 0111 1111],也即是 [-127, 127],那么-128怎么表示呢?
     *      对于8位二进制,使用原码或反码表示的范围为[-127, +127],而使用补码表示的范围是 [-128, 127]
     *      (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
     *      -1-127的结果应该是 -128,在用补码运算的结果中,[1000 0000]补就是 -128。
     *      但是注意因为实际上使用以前的-0的补码来表示-128,所以 -128 并没有原码和反码表示。
     *      (对 -128 的补码表示[1000 0000]补算出来的原码是[0000, 0000]原,这是不正确的)
     *
     * @param n 十进制整数
     * @return 二进制字符串
     */
    private static String getBinString1(int n) {
        boolean isNegative = false;
        if (n < 0) {
            isNegative = true;
            n = -1 * n;
        }
        StringBuilder sBuilder = new StringBuilder();
        while(n != 0){
            int remainder = n % 2;
            n = n / 2;
            sBuilder.append(remainder);
        }

        // 根据负数绝对值的原码,计算负数的补码
        if (isNegative){
            for (int i = sBuilder.length(); i < 31; i++)
                sBuilder.append(0);
            sBuilder.append(1);

            for (int j = 0; j < sBuilder.length()-1; j++){
                char ch = sBuilder.charAt(j)=='0' ? '1' : '0';
                sBuilder.setCharAt(j, ch);
            }

            StringBuilder tmpBuilder = new StringBuilder();
            int addition = 1;
            for (int k = 0; k < sBuilder.length(); k++){
                int emt = (sBuilder.charAt(k) == '0' ? 0 : 1) + addition;
                if (emt == 1) {
                    tmpBuilder.append(1);
                    break;
                }else{
                    tmpBuilder.append(0);
                    addition = 1;
                }
            }
            for(int i = tmpBuilder.length(); i < sBuilder.length(); i++)
                tmpBuilder.append(sBuilder.charAt(i));
            sBuilder = tmpBuilder;
        }
        return sBuilder.reverse().toString();
    }

    /**
     * 思路:
     *      1. 位操作:按位与操作,左移
     *      2. 2 的 n 次幂整数,与 number 按位与操作,
     *              如果结果大于0,则当前位数字为 1,
     *              否则,当前数字为 0
     * @param number 整数
     * @return 1 的个数
     */
    public static int numberOfOne3(int number){
        String binString = getBinString2(number);
        System.out.println(String.format("binString of %d, %s", number, binString));
        int counter = 0;
        int base = 1;
        while(base > 0){
            if((number & base) > 0) counter ++;
            base = base << 1;
        }
        if ((number & base) < 0) counter ++;   // number = 9, 0000 0000 0000 0000 0000 0000 0000 1001
        return counter;
    }

    private static String getBinString2(int number) {
        StringBuilder sBuilder = new StringBuilder();
        int base = 1;
        while(base > 0){
            int bitResult = (number & base) > 0 ? 1 : 0;  // 9 & 8 = 8
            sBuilder.append(bitResult);
            base = base << 1;
        }
        sBuilder.append((number & base) < 0 ? 1 : 0);  // number = 9, 0000 0000 0000 0000 0000 0000 0000 1001
        return sBuilder.reverse().toString();
    }

    /**
     * 思路:
     *      1. 位操作:按位与操作,无符号右移
     *      2. 2 的 n 次幂整数,与 number 按位与操作,
     *              如果结果大于0,则当前位数字为 1,
     *              否则,当前数字为 0
     * @param number 整数
     * @return 1 的个数
     */
    public static int numberOfOne4(int number){
        String binString = getBinString3(number);
        System.out.println(String.format("binString of %d, %s", number, binString));
        int counter = 0;
        // Java语言规范中,int整型类型占四个字节,总计32位
        // 对每一个位置与 1 进行按位与操作,再累加就可以求出当前数字的表示包含有多少位 1
        for (int i = 0; i < 32; i++){
            counter += (number & 1);
            number = number >>> 1;
        }
        return counter;
    }

    /**
     * 将整型数字转换为二进制字符串
     * @param number 整型数字
     * @return 二进制字符串
     */
    private static String getBinString3(int number) {
        StringBuilder sBuilder = new StringBuilder();
        for (int i = 0; i < 32; i++){
            sBuilder.append(number & 1);
            number = number >>> 1;
        }
        return sBuilder.reverse().toString();
    }

    public static void main(String[] args){
        int number = 0B1001;
        System.out.println(String.format("numberOfOne(%d) = %d", number, numberOfOne(number)));
        System.out.println(String.format("numberOfOne2(%d) = %d", number, numberOfOne2(number)));
        System.out.println(String.format("numberOfOne3(%d) = %d", number, numberOfOne3(number)));
        System.out.println(String.format("numberOfOne3(%d) = %d", number, numberOfOne4(number)));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值