【LeetCode-204】--計算[2,n]的所有質數--
轉載自:https://leetcode-cn.com/problems/count-primes/solution/ji-shu-zhi-shu-by-leetcode-solution/
統計所有小於非負整數n的質數的數量。
示例 1:
輸入:n = 10
輸出:4
解釋:小於 10 的質數一共有 4 個, 它們是 2, 3, 5, 7 。
示例 2:
輸入:n = 0
輸出:0
示例 3:
輸入:n = 1
輸出:0
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/count-primes
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。
程式碼路徑:
方法1:
最簡單粗暴的方法,雙層遍歷,沒什麼好講的
時間複雜度:O(n2)
1 public static int countPrimes2(int n) { 2 int count = 0; 3 for (int i = 2; i < n; i++) { 4 if (isPrimes(i)) { 5 count++; 6 } 7 } 8 return count; 9 } 10 11 public staticboolean isPrimes(int i) { 12 for (int j = 2; j < i; j++) { 13 if (i % j == 0) { 14 return false; 15 } 16 } 17 return true; 18 }
方法2:
基於方法1的優化,在方法1的isPrimes中存在很多次的冗餘的計算,在isPrimes方法中j不需要遍歷到i,而只需要遍歷到sqrt(n);為什麼呢,假設n=12;
12 = 2 × 6 12 = 3 × 4 12 = sqrt(12) × sqrt(12)12 = 4 × 3 12 = 6 × 2
可以看到,後兩個乘積就是前面兩個反過來,反轉臨界點就在 sqrt(n)。
換句話說,如果在 [2,sqrt(n)] 這個區間之內沒有發現可整除因子,就可以直接斷定 n 是素數了,因為在區間 [sqrt(n),n] 也一定不會發現可整除因子。
時間複雜度:O(n√n)
1 public static int countPrimes2(int n) { 2 int count = 0; 3 for (int i = 2; i < n; i++) { 4 if (isPrimes(i)) { 5 count++; 6 } 7 } 8 return count; 9 } 10 11 public static boolean isPrimes(int i) { 12 //j<i 優化 j*j<i 13 for (int j = 2; j * j < i; j++) { 14 if (i % j == 0) { 15 return false; 16 } 17 } 18 return true; 19 }
方法3:
基於方法2,我們可以思考,一開始2為質數,那麼2*i(2*i<n)的所有數是不是都不是質數了,因為能被2整除,i為3,是質數,那麼3*i的所有數也都不是質數了,那麼4剛已經被2標記不是質數了,依此類推...,該演算法由希臘數學家厄拉多塞(\rm EratosthenesEratosthenes)提出,稱為厄拉多塞篩法,簡稱埃氏篩。
時間複雜度:O(nloglog n)
1 public static int countPrimes(int n) { 2 //所有數值的狀態為1,假設所有數都為質數 3 int[] isPrime = new int[n]; 4 Arrays.fill(isPrime, 1); 5 int ans = 0; 6 for (int i = 2; i < n; ++i) { 7 //當isPrime[i]為1時說明,小於i的數都不能將i除盡,所以計數+1 8 if (isPrime[i] == 1) { 9 ans += 1; 10 if ((long) i * i < n) { 11 //這裡從i*i開始,因為 2*i,3*i,… 這些數一定在 i 之前就被其他數的倍數標記過了,和方法2的思想是一樣的,j+=i,倍數增長嘛 12 for (int j = i * i; j < n; j += i) { 13 isPrime[j] = 0; 14 } 15 } 16 } 17 } 18 return ans; 19 }
方法4:
1 public static int countPrimes1(int n) { 2 boolean[] isPrimes = new boolean[n]; 3 List<Integer> primes = new ArrayList<>(n); 4 Arrays.fill(isPrimes, true); 5 6 for (int i = 2; i < n; i++) { 7 if (isPrimes[i]) { 8 primes.add(i); 9 } 10 for (int j = 0; j < primes.size() && i * primes.get(j) < n; j++) { 11 isPrimes[i * primes.get(j)] = false; 12 if (i % primes.get(j) == 0) { 13 break; 14 } 15 } 16 } 17 18 return primes.size(); 19 }