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

来源:互联网 发布:淘宝自动收获几天 编辑:程序博客网 时间:2024/06/06 04:32

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路:这是一道位运算题。直观解法,原数&1,相当于判断原数的最后一位是不是1,如果相&的结果为1,’1’的计数加1。然后原数右移一位,即把倒数第二位移到最后一位,并将右移后的数&1,…,直到原数的第一位移到最后,然后再右移,原数变为0循环结束。

int numberOf1(int n){    int count=0;    while(n){        if((n&1)==1){            count++;        }        n=n>>1;    }    return count;}

位运算的左移:在低位补0
位运算的右移:两种情况。情况一,无符号数,高位补0。情况二,有符号数,高位补符号位。
则上面的代码就有问题,如果是一个负数,右移后补1,其最后结果不为0,程序陷入死循环。

算法改进:既然左移没问题,都是补0,我们可以左移1,然后再&原数,执行效果和原数右移相同。可以把上面的代码改进如下:

int numberOf1(int n){    int count=0;    int flag=1;    while(flag){        if((n&flag)==1){            count++;        }        flag=flag<<1;    }    return count;}

牛客网提交成功的完整代码:

public class Solution {    public static int NumberOf1(int n) {        //初始:比较最右面的是不是1        //循环:然后标志位左移1位,比较次右位是不是1        //终止:标志位移到最左面,然后再左移变为0结束        //把原来的数右移为何不可?如果是正数没问题,如果是负数,右移最高位为1,右移后次高位补1,然后最终结果为FFFFFFFF,死循环        int count=0;        int flag=1;        while(flag!=0){            if((n&flag)!=0){                count++;            }            flag=flag<<1;        }        return count;    }    public static void main(String[] args){        int n=9;        System.out.println(NumberOf1(n));    }}

程序执行的次数与整数二进制的位数相关,如果是32位,则需要循环32次,也并不太高效。

高效的解法:原数&(原数-1)
原数-1,相当于原数的二进制表示,从右边开始第一个1变0,往右,所有的0变为1,往左,保持不变。
原数&(原数-1),相当于依次从右至左,剔除原数中的1,直到为0,这样便可以对每次计数,从而得到1的个数。
牛客网提交的代码如下:

public class Solution {    public static int NumberOf1(int n) {        //初始:1100&(1100-1),得到1000,相当于减少了一个1        //循环:n=n&(n-1)        //终止:所有1都减去,最后变为0,结束        int count=0;        while(n!=0){            count++;            n=n&(n-1);        }        return count;    }    public static void main(String[] args){        int n=9;        System.out.println(NumberOf1(n));    }}
0 0
原创粉丝点击