204.计数质数

151 阅读1分钟

题目:
给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。
算法:
背景知识:
自然数:包括素数和合数和1,0不是自然数。
素数:大于1,且只能被1和他本身整除的数。
合数:大于1,除了1和他本身之外,还能被其他数(不包括0)整除的数。

解法一:暴力法
假设n不是素数,则存在 x * n / x = n, 至少有一个数落在 [2,n\sqrt{n}]之间。因此我们只要检查这个区间即可。

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 ++, 2
7 >= 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
}