剑指offer-10.二进制中1的个数

https://www.nowcoder.com/practice/8ee967e43c2c4ec193b040ea7fbb10b8?tpId=13&tqId=11164&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking

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

题解:

右移运算符 m>>n 表示把m右移n位。如果m为负数,右移之后在左边补 n 个1。
00001010>>2=00000010
10001010>>3=11110001

数字在计算机里都以二进制补码形式存储。表示的二进制位数,和编译器的位数有关系,一般是32位,即 1 在计算机中表示为:

0000 0000 0000 0000 0000 0000 0000 0001

正数的原码、反码、补码相同
负数的反码,符号位1不变,其余各位是对原码取反;
负数的补码是反码+1;
-10在计算机中的表示是:

原码:1000 0000 0000 0000 0000 0000 0000 1010
反码:1111 1111 1111 1111 1111 1111 1111 0101
补码:1111 1111 1111 1111 1111 1111 1111 0110

本题即求 十进制数 的二进制补码表示中 1 的个数。

1、错解
n 依次与 1 做与运算,如果为1,则证明n 的最后一位是1,count++,然后右移n;直到 n 全移完,最后变成 0 ,退出循环。此种方法,只对正数有效,如果为负数,每次右移,左边都会补1,n永远不能变成0 ;即出现死循环。

    public static int NumberOf1_CanNotUse(int n) {
        int count = 0;
        while (n != 0) {
            /*
            * 用1和n进行位与运算,
            * 结果要是为1则n的2进制形式
            * 最右边那位肯定是1,否则为0
            */
            if ((n & 1) == 1) {
                count++;
            }
            //把n的2进制形式往右推一位
            n = n >> 1;
        }
        return count;
    }

2、正解
用 1 和 n 的每一位做 与 运算,然后不断左移 1 ,直到 1 移出最高位,变成0。

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

3、最优解
方法2中,32位的整数需要循环32次,下面的解法,整数中有几个1 就只需循环几次。

我们发现把一个整数减去1 ,都是把最右边的 1 变成 0。如果它的右边还有0 的话,所有的0 都变成1,而它左边所有位都保持不变。

我们可以把一个整数和它减去 1 的结果做位与运算,相当于把它最右边的1 变成0。

以 1100为例,它减去1 得1011。把1100 和 1011 做位与运算,得到结果是1000。即把1100 最右边的1 变成了0。

所以可以利用这个性质,一个整数的二进制表示中有多少个 1 ,就可以进行多少次这样的操作。

public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while (n != 0) {
            ++count;
            n = (n - 1) & n;
        }
        return count;
    }
}

相关题目:

1、用一条语句判断一个整数是否是 2 的整数次方。

解:一个整数如果是2 的整数次方,那么它的二进制表示中有且只有一位(最高位)是1,而其他所有位都是 0 。根据下列性质,看结果是否是0 ,即可判断。

一个整数和它减去 1 的结果做位与运算,相当于把它最右边的1 变成0。

2、输入两个整数 m 和 n ,计算需要改变m 的二进制表示中的多少位才能得到 n 。比如 10 的二进制是 1010 ,13的二进制是 1101 ,需要改变 1010 中的3位 才能得到 1101。

解:利用异或,分为两步解决:第一步求这两个数的异或,第二步统计异或结果中 1 的位数。

猜你喜欢

转载自blog.csdn.net/zxm1306192988/article/details/80839885
今日推荐