统计所有小于非负整数 n 的质数的数量。
示例:
输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
解题思路
这个问题非常简单。首先想到的通过暴力破解
class Solution:
def countPrimes(self, n):
"""
:type n: int
:rtype: int
"""
res = list()
for i in range(2, n):
if self.isPrime(i):
res.append(i)
return len(res)
def isPrime(self, n):
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, int(pow(n, 0.5))+1):
if n % i == 0:
return False
return True
超时了,只能换个方法。使用埃拉托色尼筛网法,给出要筛数值的范围n,找出 以内的素数。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个素数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个素数5筛,把5留下,把5的倍数剔除掉;不断重复下去…。
class Solution:
def countPrimes(self, n):
"""
:type n: int
:rtype: int
"""
primes = [0] * n
for i in range(2, n):
j = 2
while i * j < n:
primes[i*j] = 1
j += 1
return sum(primes)
依旧超时,我屮艸芔茻。接着对埃拉托色尼筛网法进行优化,优化思路也很简单,就是将原来的串行法改为并行法(也就是一次性将所有的标记标上)。
class Solution:
def countPrimes(self, n):
"""
:type n: int
:rtype: int
"""
if n < 2:
return 0
p = [1] * n
for i in range(2, int(n ** 0.5) + 1):
if p[i] == 1:
p[i*i:n:i] = [0] * ((n - i*i - 1) // i + 1) # faster
return sum(p) - 2
最后使用欧拉函数线性筛,主要要解决这样的问题:
我们发现在上面的筛法中有的数字是多个质数的倍数,也就是说它可能会被重复计算多次,比如说6同时是2与3的倍数,它在计算时就被访问了两次,这样会导致效率低下,所以欧拉筛针对这点进行了优化。
class Solution
{
public:
int countPrimes(int n)
{
vector<int> primes(n, 0); //记录第i个质数
deque<bool> flag(n, false);
int count = 0;
for (int i = 2; i < n; ++i)
{
if (!flag[i]) primes[++count] = i;
for (int j = 1; j <= count and primes[j]*i <= n; ++j)
{
flag[primes[j]*i] = true;
if (i % primes[j] == 0) break;
}
}
return count;
}
};
但是这种做法在提交的时候只跑出来68ms
的成绩。注意上面我没有使用数组,因为在windows
下不支持可以变长数组,在新的标准中也移除这一特性。如果这里使用可以变长数组的话,速度会快上许多。
讲道理这道题目应该不能算是简单的题目吧。
reference:
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
https://blog.csdn.net/nixinyis/article/details/64131351?utm_source=blogxgwz8
https://stackoverflow.com/questions/16004407/a-fast-prime-number-sieve-in-python
https://www.cnblogs.com/BigYellowDog/p/9695648.html
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!