剑指offer第二版-15.二进制中1的个数(位运算)

本系列导航:剑指offer(第二版)java实现导航帖

面试题14:剪绳子

题目要求:
实现一个函数,输入一个int型整数,输出该数字在计算机中二进制表示形式的1的个数。例如9->1001,输出2;-3->11111111111111111111111111111101,输出31。

解题思路:
考查位运算,此题要注意负数的处理。首先要明确计算机中,数字是以补码的形式存储的,原码反码补码不清楚的话请自己谷歌百度。其次,明确位运算符,与&,或|,非~,异或^,<<左移位,>>带符号右移位,>>>无符号右移位(java有此符号,c++没有)

  • 解法一:将数字无符号右移,直到为0。
  • 解法二:使用一个标记,初始为1,让标记值与原输入数字异或,然后标记值左移。解法一是原数字右移,而解法二是标记左移,从java来看思路类似但换了个角度;但这个思路在C++就很关键,因为C++中没有>>>运算符,只能用解法二。
  • 解法三:没接触过的人应该会觉得比较新颖。对于二进制数有如下结论:【把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于把原整数的二进制表示形式的最右边的1变成0】。比如1001,执行一次上述结论,1001&1000=1000,将最右边的1改为了0;再执行一次,1000&0111=0000,第二个1也改成了0。因此能执行几次该结论,就有几个1。对于解法一二,都需要循环32次,判断每一个比特位是否为1,而解法三,循环次数等于比特位为1的个数。时间上是有改进的。
package chapter2;
/**
 * Created by ryder on 2017/7/6.
 * 二进制中的1的个数
 */
public class P100_NumberOf1InBinary {
    public static int numberOfOne1(int n){
        int count=0;
        while(n!=0){
            if((n&1)!=0)
                count++;
            n>>>=1;
        }
        return count;
    }
    public static int numberOfOne2(int n){
        int count=0;
        int flag=1;
        while(flag!=0){
            if((n&flag)!=0)
                count++;
            flag<<=1;
        }
        return count;
    }
    public static int numberOfOne3(int n){
        int count=0;
        while(n!=0){
            n = n&(n-1);
            count++;
        }
        return count;
    }
    public static void main(String[] args){
        System.out.println(numberOfOne1(3));
        System.out.println(numberOfOne1(-3));
        System.out.println(numberOfOne2(3));
        System.out.println(numberOfOne2(-3));
        System.out.println(numberOfOne3(3));
        System.out.println(numberOfOne3(-3));
    }
}

运行结果

2
31
2
31
2
31

其他相关

  • 使用一条语句判断一个正整数是不是2的整数次方
    public static boolean isPowerOfTwo(int n){
        return (n&(n-1))==0;
    }
  • 输入两个整数m,n,计算最少需要改变m的多少位才能得到n
    先对m,n进行异或,再统计异或结果中1的位数

你可能感兴趣的:(剑指offer第二版-15.二进制中1的个数(位运算))