- 操作系统:ubuntu22.04
- IDE:Visual Studio Code
- 编程语言:C++11
题目描述:
请实现一个函数 int NumberOf1(int n),输入一个整数(可能为负数),输出该数二进制表示中 1 的个数。例如:
把 9 表示成二进制是 1001,有 2 个 1;
把 -1 表示成二进制在补码形式下全是 1(32位系统下是 32 个 1)。
示例
bash
输入: n = 9
输出: 2
输入: n = -1
输出: 32
解题思路
这个问题主要考察的是对 二进制和位运算的理解,以及如何处理 负数(补码表示)。
以下是几种常见解法:
方法一:逐位与操作(推荐)
cpp
int NumberOf1(int n)
{
int count = 0;
while (n != 0)
{
++count;
n = n & (n - 1); // 消除最右边的一个 1
}
return count;
}
优点:
- 不需要考虑正负;
- 效率高,循环次数等于 1 的个数;
- 利用了 n & (n - 1) 特性:每次消去一个 1。
方法二:右移判断每一位是否为 1
cpp
int NumberOf1(int n)
{
int count = 0;
unsigned int flag = 1; // 使用无符号数来避免右移时出错
while (flag != 0)
{
if (n & flag)
++count;
flag <<= 1;
}
return count;
}
说明:
- 循环 32 次(32位整数);
- 每次用 flag 来测试某一位是否为 1;
- 对于负数也能正确处理(因为使用了无符号变量);
方法三:使用 C++ 内建函数(C++20 起)
如果你使用的是 C++20 或更高版本,可以使用标准库提供的函数:
cpp
#include <bit>
int NumberOf1(int n) {
return std::popcount(static_cast<unsigned int>(n));
}
说明:
- std::popcount() 返回一个数中 1 的数量;
- 需要将 int 强转为 unsigned int 来保证行为一致。
示例代码
cpp
#include <iostream>
using namespace std;
class Solution {
public:
int NumberOf1( int n )
{
int count = 0;
while ( n != 0 )
{
++count;
n = n & ( n - 1 ); // 消除最右边的 1
}
return count;
}
};
int main()
{
Solution solution;
cout << "9 中 1 的个数:" << solution.NumberOf1( 9 ) << endl; // 输出 2
cout << "-1 中 1 的个数:" << solution.NumberOf1( -1 ) << endl; // 输出 32
return 0;
}
运行结果
bash
9 中 1 的个数:2
-1 中 1 的个数:32