[LeetCode] #204 计数质数
统计所有小于非负整数 n
的质数的数量。
输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
暴力解法,每个数都判断是否有因数(超时)
class Solution { public int countPrimes(int n) { int ans = 0; for (int i = 2; i < n; ++i) { ans += isPrime(i) ? 1 : 0; } return ans; } public boolean isPrime(int x) { for (int i = 2; i < x; ++i) { if (x % i == 0) { return false; } } return true; } }
暴力法优化
考虑到如果 y 是 x 的因数,那么 x/y 也必然是 x 的因数,因此我们只要校验 y 或者 x/y 即可。而如果我们每次选择校验两者中的较小数,则不难发现较小数一定落在[2, 2^(1/2)]的区间中,因此我们只需要枚举 [2, 2^(1/2)] 中的所有数
class Solution { public int countPrimes(int n) { int ans = 0; for (int i = 2; i < n; ++i) { ans += isPrime(i) ? 1 : 0; } return ans; } public boolean isPrime(int x) { for (int i = 2; i * i <= x; ++i) { if (x % i == 0) { return false; } } return true; } }
埃氏筛法
如果 x 是质数,那么大于 x 的 x 的倍数2x,3x,4x...一定不是质数
class Solution { public int countPrimes(int n) { int[] isPrime = new int[n]; Arrays.fill(isPrime, 1); int ans = 0; for (int i = 2; i < n; ++i) { if (isPrime[i] == 1) { ans += 1; if ((long) i * i < n) { for (int j = i * i; j < n; j += i) { isPrime[j] = 0; } } } } return ans; } }
知识点:
public static void fill(int[] a, form, to, int var)
a--数组
form--替换开始位置(包括)
to--替换结束位置(不包括)
var--要替换的值
(如果不传入from和to,则a数组全部值替换为var)
当出现i*i时,需要防溢出
总结:无