JZ15 二进制中1的个数

185 阅读2分钟

Day18 2023/01/25

题目链接

难度:简单

题目

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

数据范围:231<=n<=23112^{31}<=n<=2^{31}−1

即范围为:2147483648<=n<=2147483647−2147483648<=n<=2147483647

示例

输入:10
返回值:2
说明:十进制中10的32位二进制表示为0000 0000 0000 0000 0000 0000 0000 1010,其中有两个1。     

思路一


遍历整数n二进制的每一位,如果为 1 则计数器加1,最后返回计数器。其中通过移位运算实现遍历每一位,通过按位与运算确定该位是否为1。 具体做法:

  • 遍历二进制的32位,通过向左移位运算。
  • 将移位后的1与数字n进行按位与运算,结果不为0,计数器就加1。

思路二


我们可以在思路一的基础上进行优化,通过性质:n&(n−1)(与运算),会将n的二进制中最低位的1变成0。 具体做法:

  • 当n不为零的时候进入循环。
  • 与n-1做按位与运算(去掉最低位的1),并统计次数。
    图示:

D2B5CA33BD970F64A6301FA75AE2EB22.png

关键点


  • 按位与运算符“&”是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位都为1时,结果位才为1。参与运算的两个数均以补码出现。(知识点✅)

  • 思路一中如何确定该位是否为1的,因为数字1的二进制除最低为1外,其余位都为0,当它与数字n进行按位与运算后,当前位若为1的话,最后结果只有最后1位为1,其余全为0,否则全为0。

  • 思路二中每次n&(n-1)(与运算)后,n的二进制数中最低为的1就变为0,直到最后所有位都为0。

算法实现


c++代码实现-按位比较

#include <iostream>
using namespace std;

int NumberOf1(int n) {
    int num = 0;                          //计数器
    for (int i = 0; i < 32; i++) {
        if((n & (1 << i)) != 0) num ++;  //判断是否为1
    }
    return num;  // 返回结果
}

int main() {
    int res = NumberOf1(10);
    cout << "其中1的个数为:"<< res;
}
  • 时间复杂度 O(n)O(n) --- n为二进制数的位数,需要遍历一次
  • 空间复杂度 O(1)O(1) --- 常数级变量,没有额外的辅助空间

c++代码实现-按位比较优化

#include <iostream>
using namespace std;

int NumberOf1(int n) {
    int res = 0;
    //当n为0时停止比较
    while(n){  
        n &= n - 1; //消掉一个1
        res++;
    }
    return res;  //返回结果
    }

int main() {
    int res = NumberOf1(10);
    cout << "其中1的个数为:"<< res;
}
  • 时间复杂度 O(logn)O(logn) --- n为输入的整数,最坏情况下循环次数等于n中1的个数。
  • 空间复杂度 O(1)O(1) --- 常数级变量,没有额外的辅助空间

总结

  • 本题涉及二进制数的一些运算,这是比较基础的知识点,这里还介绍了“按位与运算”(可以了解一下)!