数学类的题目就是技巧性太强,而且属于知识点型的,知道就很简单,不知道就一点都不知道怎么下手。

自己想了一个思路,与1进行按位与,结果为1时计数加1,然后把数值一次向右移1位,这样计算,结果只能针对正整数,因为负数的右移左端补的是1.

还是看了题解才想明白。

解法一、将掩码左移

即用0b1作为掩码,不是将原数值n依次右移(避免负数问题),而是将掩码依次左移:

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

这个地方涉及到一个Java的语言特性:如果我们直接将0b1左移超过该类型的最大位数,这里即int类型的32位,那么编译器将直接对左移的次数按该类型的最大位数取余,也就是说我们如果指定0b1 << 33,实际上编译器处理后,变成了0b1 << 1.

而如果我们将数值一次向左移动一位,移动33次,则编译器不会进行处理,而最终得到的将是0.

解法二

数值n和n-1做按位与运算的结果等于消除n的二进制表示中最右侧的1,这个知识点了解后就非常巧妙。

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