Day18 2023/01/25
难度:简单
题目
输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。
数据范围:
即范围为:
示例
输入: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),并统计次数。
图示:
关键点
-
按位与运算符“&”是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位都为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;
}
- 时间复杂度 --- n为二进制数的位数,需要遍历一次
- 空间复杂度 --- 常数级变量,没有额外的辅助空间
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;
}
- 时间复杂度 --- n为输入的整数,最坏情况下循环次数等于n中1的个数。
- 空间复杂度 --- 常数级变量,没有额外的辅助空间
总结
- 本题涉及二进制数的一些运算,这是比较基础的知识点,这里还介绍了“按位与运算”(可以了解一下)!