- Count Primes
Count the number of prime numbers less than a non-negative number, n.
Example
Example 1:
Input: n = 2
Output: 0
Example 2:
Input: n = 4
Output: 2
Explanation:2, 3 are prime number
解法1:普通筛法。
记得i循环到sqrt(n)就可以了。不知道有没有更好的办法。
空间复杂度O(n),时间复杂度O(nloglogn)。这里O(nloglogn)接近O(n),因为loglogn接近于常数。
class Solution {
public:
/**
* @param n: a integer
* @return: return a integer
*/
int countPrimes(int n) {
if (n == 1) return 0;
int sqrtn = sqrt(n);
vector<int> filter(n, 1);
for (int i = 2; i <= sqrtn; ++i) {
int j = i << 1;
while (j < n) {
filter[j] = 0;
j += i;
}
}
int count = 0;
for (int i = 1; i <= n; ++i) {
if (filter[i] == 1) {
count++;
}
}
return count - 1; //1 is not prime
}
};
解法2:也是普通筛法。
下面的解法也可以。但当n>=46350后会出错,因为n*n>MAX_INT
class Solution {
public:
/**
* @param n: a integer
* @return: return a integer
*/
int countPrimes(int n) {
vector<int> flags(n + 1, 0);
for (int i = 2; i <= n; ++i) {
if (flags[i]) continue;
//fails after i >=46350 as i*i exceeds MAX_INT
for (int j = i * i; j <= n; j += i) {
flags[j] = 1;
}
}
int count = 0;
for (int i = 2; i < n; ++i) {
if (!flags[i]) count++;
}
return count; //1 is not prime
}
};
解法3:线性筛法。时间复杂度O(n)。很不错!
关于线性筛法的介绍见
https://zhuanlan.zhihu.com/p/42609585
class Solution {
public:
/**
* @param n: a integer
* @return: return a integer
*/
int countPrimes(int n) {
vector<int> primes(n + 1, 0); //primes[i]: 0 => unprocessed, -1 => non-prime, >0 => a prime-number
int count = 0;
for (int i = 2; i < n; ++i) {
if (!primes[i]) {
primes[count++] = i;
}
for (int j = 0; j < count; ++j) {
int product = primes[j] * i;
if (product > n) break;
primes[product] = -1; //just show it is not prime-number. It can be any number except 0.
if (i % primes[j] == 0) break;
}
}
return count;
}
};
解释如下:
参考https://zhuanlan.zhihu.com/p/42609585
(3).对于一个数k,总是进行从nprime[0]~nprimej,直到if(n%prime[j]==0)成立时break掉
这是这个算法的精髓所在,所以弄清楚原因是十分必要的!!!
对于一个数c=ab(b为c的最小质因数),当通过该算法的循环循环至cb时,易得此时c%b==0,如果此时继续循环至b后面的一个素数d,则有:cd=abd=(ad)b,因为d>b,所以ad>c。当循环从c继续查找到ad时我们发现当ad再次与素数b想乘时,就又对c*d进行了一次操作,出现了冗余,所以在if(n%prime[j]==0)成立时要将该层循环break掉;
举个例子,对于一个数9,92=18将18标记为合数,循环继续;93=27将27标记为合数,此时发现9%3=0,循环退出。如果将循环继续下去会出现筛除95=45的情况,而45=153,在15时会被在筛去一次,故不可行