LeetCode 762 二进制表示中质数个计算置位
题目描述
给定两个整数 L 和 R,找到闭区间 [L, R] 范围内,计算置位位数为质数 的整数个数。
(计算置位位数:二进制表示中 1 的个数)
示例:
输入: L = 6, R = 10
输出: 4
解释:
6 (110) -> 2 个 1,2 是质数
7 (111) -> 3 个 1,3 是质数
8 (1000) -> 1 个 1,1 不是质数
9 (1001) -> 2 个 1,2 是质数
10(1010) -> 2 个 1,2 是质数
共计 4 个。
解题思路
题目核心有两个步骤:
- 对区间内每个数,统计其二进制中
1的个数。 - 判断该个数是否为质数。
关键点分析
- 二进制
1的个数可以通过位运算快速得到:不断右移并检查最低位。 - 质数判断:由于本题数据范围
L, R <= 10^6,二进制最多有 20 位(2^20 = 1048576),因此1的个数最多为 20。我们可以预先将 20 以内的所有质数列出(2, 3, 5, 7, 11, 13, 17, 19),直接查表即可,无需每次判断质数。
代码实现(C++)
cpp
class Solution {
public:
int countPrimeSetBits(int left, int right) {
unordered_set<int> primes{2, 3, 5, 7, 11, 13, 17, 19}; // 20 以内的所有质数
int res = 0;
for (int i = left; i <= right; ++i) {
int s = 0;
// 计算 i 的二进制中 1 的个数
for (int j = i; j; j >>= 1) s += j & 1;
res += primes.count(s);
}
return res;
}
};
代码解释
-
质数集合
unordered_set<int> primes{2,3,5,7,11,13,17,19};因为最大可能置位位数不超过 20,所以预先存储 20 以内的质数,用于 O(1) 判断。
-
遍历区间
for (int i = left; i <= right; ++i)枚举区间内每个数。 -
计算置位位数
内层循环
for (int j = i; j; j >>= 1)将j不断右移,直到j变为 0。
s += j & 1每次取最低位(0 或 1)累加到s中,最终s即为二进制中 1 的个数。 -
结果累加
if (primes.count(s)) ++res;若s是质数,则答案加 1。
复杂度分析
- 时间复杂度 :区间长度为
n = right - left + 1,每个数需要循环其二进制位数,最多 20 次,因此总时间复杂度为O(n * 20),即线性时间。 - 空间复杂度:仅使用了常数大小的额外空间(质数集合)。
总结
本题巧妙之处在于数据范围决定了置位位数有限,因此可以预先列出质数,避免了动态判断质数的开销。位运算统计 1 的个数也是非常基础且高效的技巧