面试题15:二进制中1的个数

题目:

请实现一个函数,输入一个整数,输出该整数的二进制表示中1的个数。例如,把9表示成二进制是1001,有2个是1。因此,如果输入9,则该哈数输出2。如果输入负数,则统计该数字二进制补码中的1的个数。

分析:

可能引起死循环的解法:

先判断二进制中最右边一位是不是1;接着把输入的整数右移一位,此时原来处于从右边数起第二位被移到最右边了,再判断是不是1;这样每移动一位,直到整个整数变成0为止。判断最右边一位是不是1,只需要将这个数和1做与运算看结果是不是0就知道了。

假设,这个数字是负数,在右移的过程中,要保持最左边一位符号位不变,最左侧添加一个1,在不断右移的过程中,这个数字最终变成了0xFFFFFFFF,于是就陷入了死循环。

常规解法:

为了避免死循环,我们可以不右移数字,而是不断的左移1,从而判断每一位是1还是0。

能给面试官带来惊喜的解法:

考虑将数字减去1。假设二进制数字是1111,减去1是1110;假设数字是1100,减去1是1011。将1111和1110做与运算得到1110,将1100和1011做与运算得到1000。对于1111到1110,最后一个1不见了,对于1100到1000,也是最后一个1不见了。所以,可以通过n&(n-1)的方式不断去掉二进制中最后一个1,当这个数字变成0的时候,就能统计出来1的数量了。此时的时间复杂度由二进制中1的数量决定,而不是二进制的位数决定,这是一个常数级别的优化。

解法:

可能引起死循环的解法:

package com.wsy;

public class Main {
    public static void main(String[] args) {
        int n = 15;
        int count = getCountOf1(n);
        System.out.println(count);
    }

    public static int getCountOf1(int n) {
        int count = 0;
        while (n != 0) {
            if ((n & 1) == 1) {
                count++;
            }
            n >>= 1;
        }
        return count;
    }
}

常规解法:

package com.wsy;

public class Main {
    public static void main(String[] args) {
        int n = 15;
        int count = getCountOf1(n);
        System.out.println(count);
    }

    public static int getCountOf1(int n) {
        int count = 0;
        int flag = 1;
        while (flag != 0) {
            if ((n & flag) != 0) {
                count++;
            }
            flag <<= 1;
        }
        return count;
    }
}

能给面试官带来惊喜的解法:

package com.wsy;

public class Main {
    public static void main(String[] args) {
        int n = 15;
        int count = getCountOf1(n);
        System.out.println(count);
    }

    public static int getCountOf1(int n) {
        int count = 0;
        while (n != 0) {
            n &= (n - 1);
            count++;
        }
        return count;
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值