题目描述
解题思路
枚举 [ left , right ] [\textit{left},\textit{right}] [left,right] 范围内的每个整数,挨个判断是否满足题目要求,对于每个数 x x x需要解决两个问题:
- 如何求出
x
x
x的二进制中的
1
1
1的个数?
- 库函数
Integer.bitCount()
while
循环统计 +lowbit
操作:x&-x
只保留整数 x x x最低位的 1 1 1
- 库函数
- 如何判断一个数是否为质数?
- 枚举 [ 2 , x ] [2,\sqrt{x}] [2,x]中的每个数 y y y,判断 y y y是否为 x x x的因数,以此来判断一个数是否为质数
- 打表:一个
int
的二进制表示不超过 32,可以将 32 以内的质数进行打表 - 打表+比特掩码:用一个二进制数 mask = 665772 = 1010001010001010110 0 2 \textit{mask}=665772=10100010100010101100_{2} mask=665772=101000101000101011002 来存储这些质数,其中 mask \textit{mask} mask 二进制的从低到高的第 i i i 位为 1 表示 i i i 是质数,为 0 表示 i i i 不是质数。
代码一:库函数+枚举
class Solution {
public int countPrimeSetBits(int left, int right) {
int ans = 0;
for (int x = left; x <= right; x++) {
if (isPrime(Integer.bitCount(x))) {
ans++;
}
}
return ans;
}
// 时间复杂度O(Sqrt(x))
private boolean isPrime(int x) {
if (x < 2) {
return false;
}
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) {
return false;
}
}
return true;
}
}
Integer.java
:
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
-
时间复杂度: O ( ( right − left ) log right ) O((\textit{right}-\textit{left})\sqrt{\log\textit{right}}) O((right−left)logright)。二进制中 1 的个数为 O ( log right ) O(\log\textit{right}) O(logright),判断值为 x x x 的数是否为质数的时间为 O ( x ) O(\sqrt{x}) O(x)
-
空间复杂度: O ( 1 ) O(1) O(1)
代码二:lowbit+打表
class Solution {
public int countPrimeSetBits(int left, int right) {
int ans = 0;
int[] primes = new int[]{2,3,5,7,11,13,17,19,23,29,31};
boolean[] hash = new boolean[32];
for (int p : primes) {
hash[p] = true;
}
for (int x = left; x <= right; x++) {
if (hash[countBit(x)]) {
ans++;
}
}
return ans;
}
// 时间复杂度O(log x)
private int countBit(int x) {
int cnt = 0;
while (x != 0) {
x -= (x & -x);
cnt++;
}
return cnt;
}
}
-
时间复杂度: O ( ( r i g h t − l e f t ) × log r i g h t ) O((right - left) \times \log{right}) O((right−left)×logright)
-
空间复杂度: O ( C ) O(C) O(C)
代码三:库函数+比特掩码
class Solution {
public int countPrimeSetBits(int left, int right) {
int ans = 0;
for (int x = left; x <= right; ++x) {
if (((1 << Integer.bitCount(x)) & 665772) != 0) {
++ans;
}
}
return ans;
}
}
-
时间复杂度: O ( right − left ) O(\textit{right}-\textit{left}) O(right−left)
-
空间复杂度: O ( 1 ) O(1) O(1)