emmmm太久没做题连筛素数都忘了。又看了一遍算法,记录一下。
题目:求小于N的素数的个数。
链接:计数质数
代码:
class Solution {
public:
int getPrime(int n)
{
vector<int> prime;
vector<bool> check(n,false);
for(int i=2;i<n;i++)
{
if(!check[i])
prime.push_back(i);
for(int j=0;j<prime.size();j++)
{
if(prime[j]*i>=n)
break;
check[i*prime[j]]=true;
if(i%prime[j]==0) // 重点
break;
}
}
return prime.size();
}
int countPrimes(int n) {
return getPrime(n);
}
};
核心思想是,一个素数的倍数一定不是素数,把它的倍数标记,不计入就可以了。
这个算法筛求标记数组的时候,不是对于一个素数p,遍历它所有的倍数,而是对于当前记录的所有素数prime[],标记每个元素prime[j]的i倍。
为了避免重复筛到,重点是 if(i%prime[j]==0) 这句话。
思考一下,若
i
i%prime[j]==0
i,意味着
i
=
p
r
i
m
e
[
j
]
∗
t
i=prime[j]*t
i=prime[j]∗t。t是某一个倍数。那么对于下次遍历
p
r
i
m
e
[
j
+
1
]
prime[j+1]
prime[j+1],可知,
i
∗
p
r
i
m
e
[
j
+
1
]
=
p
r
i
m
e
[
j
]
∗
(
t
∗
p
r
i
m
e
[
j
+
1
]
)
i*prime[j+1]=prime[j]*(t*prime[j+1])
i∗prime[j+1]=prime[j]∗(t∗prime[j+1])。
(
t
∗
p
r
i
m
e
[
j
+
1
]
)
(t*prime[j+1])
(t∗prime[j+1])可以看做另一个倍数t’。也就是说,后续某次遍历到
i
=
t
′
=
(
t
∗
p
r
i
m
e
[
j
+
1
]
)
i=t'=(t*prime[j+1])
i=t′=(t∗prime[j+1])时,一定会将
i
∗
p
r
i
m
e
[
j
+
1
]
i*prime[j+1]
i∗prime[j+1]标记。j之后的元素也是同理,这样就可以break掉了。