题目:
给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。
算法:
背景知识:
自然数:包括素数和合数和1,0不是自然数。
素数:大于1,且只能被1和他本身整除的数。
合数:大于1,除了1和他本身之外,还能被其他数(不包括0)整除的数。
解法一:暴力法
假设n不是素数,则存在 x * n / x = n, 至少有一个数落在 [2,]之间。因此我们只要检查这个区间即可。
func countPrimes(n int) int {
cnt := 0
for i := 2; i < n; i ++ {
if isPrime(i) {
cnt ++
}
}
return cnt
}
func isPrime(num int) bool {
for i := 2; i * i <= num; i ++ {
if num % i == 0 {
return false
}
}
return true
}
方法二: 埃氏筛
所有的合数最终可以分解成多个质数之积。 如x是质数,则x,2x,3x,4x...都是合数。我们从2开始,用数组primes保存i是素数还是合数,i=0素数,i=1合数。初始状态所有数为素数。
假设n=10,
n=2,质数,cnt ++, primes[2]=0, primes[4],primes[6],primes[8]=1
n=3,质数,cnt ++, primes[3]=0, primes[6],primes[9]=1
n=4,合数,跳过
n=5,质数,cnt ++, 25 >= 10跳过
n=6,合数,跳过
n=7,质数,cnt ++, 27 >= 10跳过
n=6,合数,跳过
n=9,质数,cnt ++, 2*9 >= 10跳过
func countPrimes(n int) int {
state := make([]int, n)
cnt := 0
for i := 2; i < n; i ++ {
if state[i] == 0 {
cnt ++
for j := 2; j * i < n; j ++ {
state[j * i] = 1
}
}
}
return cnt
}
方法二: 埃氏筛 优化:
func countPrimes(n int) int {
state := make([]int, n)
cnt := 0
for i := 2; i < n; i ++ {
if state[i] == 0 {
cnt ++
// 当这样循环时:for j := 2; j * i < n; j ++
// 2i, 3i, 4i...(i-1)i已经分别在在i=2,3,4,...i-1的时候被计算过了,所以直接从i*i开始计算
for j := i; j * i < n; j ++ {
state[j * i] = 1
}
}
}
return cnt
}