一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情 。
给你两个整数 left 和 right ,在闭区间 [left, right] 范围内,统计并返回 计算置位位数为质数 的整数个数。
计算置位位数 就是二进制表示中 1 的个数。
- 例如,
21的二进制表示10101有3个计算置位。
示例 1:
输入:left = 6, right = 10
输出:4
解释:
6 -> 110 (2 个计算置位,2 是质数)
7 -> 111 (3 个计算置位,3 是质数)
9 -> 1001 (2 个计算置位,2 是质数)
10-> 1010 (2 个计算置位,2 是质数)
共计 4 个计算置位为质数的数字。
示例 2:
输入:left = 10, right = 15
输出:5
解释:
10 -> 1010 (2 个计算置位, 2 是质数)
11 -> 1011 (3 个计算置位, 3 是质数)
12 -> 1100 (2 个计算置位, 2 是质数)
13 -> 1101 (3 个计算置位, 3 是质数)
14 -> 1110 (3 个计算置位, 3 是质数)
15 -> 1111 (4 个计算置位, 4 不是质数)
共计 5 个计算置位为质数的数字。
注意到 因此二进制中 1 的个数不会超过 19,而不超过 19 的质数只有
我们可以用一个二进制数 mask=665772=101000101000101011002 来存储这些质数,其中 mask 二进制的从低到高的第 i 位为 1 表示 i 是质数,为 0 表示 iii 不是质数。
设整数 xxx 的二进制中 1 的个数为 c,若 mask 按位与 不为 0,则说明 c 是一个质数。
var countPrimeSetBits = function(left, right) {
let ans = 0;
for (let x = left; x <= right; ++x) {
if (((1 << bitCount(x)) & 665772) != 0) {
++ans;
}
}
return ans;
};
const bitCount = (x) => {
return x.toString(2).split('0').join('').length;
}
代码优化
对于第一步,还有一种方式是 n &= n - 1 判断 1 的个数,具体可查看我的这篇题解 剑指 Offer 15. 二进制中1的个数 利用位运算的特殊性质带你使用两种新思路解题 对于第二步,由于整数的二进制形式最多只有 32 位,即最大范围是 2^32,所以可以先通过打表的方式,将 32 以内的素数存到一个集合里,那么第二步直接判断 第一步得出来的个数是否在集合里就行了
/**
* @param {number} left
* @param {number} right
* @return {number}
*/
var countPrimeSetBits = function(left, right) {
let result = 0;
for(let i = left; i <= right; i++) {
let num = have1Num(i); // num 值为 i 这个数的二进制形式中,中含 1 的个数
result += isPrimse(num); // 计算 num 是不是素数,直接 += 即可
}
return result;
};
// 该数的二进制形式中,含 1 的个数
function have1Num(num) {
let result = 0;
while(num) {
result += num & 1;
num >>= 1;
}
return result;
}
// 判断是否是质数
function isPrimse(num) {
// 0 和 1 不是质数
if(!num || num === 1) return 0;
for(let i = 2; i * i <= num; i++) {
// num 对于 i 的余数不是0,那么不是质数直接返回
if(num % i === 0) {
return 0;
}
}
return 1;
}