算法思路一:位运算右移

解题思路:

判断 n 最右一位是否为 11 ,根据结果计数。将 n 右移一位(本题要求把数字 n 看作无符号数,因此使用 无符号右移 操作)
算法流程:
初始化数量统计变量 res = 0。
循环逐位判断: 当 n = 0时跳出。
res += n & 1 : 若 n & 1 = 1,则统计数 resres 加一。
n >>= 1 : 将二进制数字 n 无符号右移一位( Java 中无符号右移为 ">>>" ) 。
返回统计数量 res 。

图解:
n = 10
步骤 操作 n二进制
res
1
1010 0
2 右移1位 0101 1
3 右移1位
0010 1
4 右移1位
0001 2
5 右移1位
0000 2
返回res = 2

代码展示:

public class Solution {
    public int NumberOf1(int n) {
        int cnt = 0;
        // 循环直到n == 0
        while(n != 0){
            // 判断 n & 1 是否为0
            if((n & 1)!=0)cnt++;
            //将n进行无符号右移
            n = n>>>1;
        }
        return cnt;
    }
}

复杂度分析:
时间复杂度 O(logn) : 此算法循环内部仅有 移位、与、加 等基本运算,占用 O(1) ;逐位判断需循环 logn 次,其中n 代表数字n 最高位 1 的所在位数。
空间复杂度 O(1) : 变量 res使用常数大小额外空间。

算法思路二:巧用 n&(n-1)

n&(n - 1),其预算结果恰为把 n 的二进制位中的最低位的 1 变为 0之后的结果
算法流程:
初始化数量统计变量 res
循环消去最右边的 1 :当 n = 0时跳出。
res += 1 : 统计变量加 1 ;
n &= n - 1 : 消去数字 n 最右边的 1 。
返回统计数量 res。

图解:


代码展示:
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        count = 0
        # n < 0 则需要将其进行转换
        if n<0:
            n = n & 0xffffffff
        # 循环计算,将二进制最右边的1变成0
        # 统计循环次数,即为 二进制中1的数量
        while n:
            count += 1
            n = (n-1) & n
        return count

复杂度分析:

时间复杂度:O(log n)。循环次数等于 n 的二进制位中 1 的个数,最坏情况下 n 的二进制位全部为 1。我们需要循环 logn 次。
空间复杂度:O(1),我们只需要常数的空间保存若干变量