LeetCode 204. Count Primes(C++版)
阿新 • • 發佈:2019-01-28
Description:
Count the number of prime numbers less than a non-negative number, n.
思路分析:方法一:我們知道大於2的偶數肯定不是素數。所以遍歷小於n的奇數,判斷是否為素數,是,count++。
class Solution { public: bool isPrime(int n){ if(n == 1) return false; for(int i = 2; i <= sqrt(n); i ++){ if(n % i == 0) return false; } return true; } int countPrimes(int n) { //首先>2的偶數肯定不是質數,只需要判斷奇數 int cnt = 0; if(n > 2) cnt ++;//2是質數 for(int i = 3; i < n; i +=2 ){ if(isPrime(i)) cnt ++; } return cnt; } };
但是這種思路超時。
方法二:
我們前面的思路可不可以優化呢?可以的——可以在判斷是否為素數這個函式上改進。由於我們在主函式中傳進來的引數一定為奇數,所以一定不能被偶數整除,那麼可以把 i 改為從3開始每迴圈一次,增加2。
class Solution { public: bool isPrime(int n){ if(n == 1) return false; for(int i = 3; i <= sqrt(n); i += 2){//因為我們傳進來的數一定不是偶數,所以可以直接只判斷能都被奇數整除 if(n % i == 0) return false; } return true; } int countPrimes(int n) { //首先>2的偶數肯定不是質數,只需要判斷奇數 int cnt = 0; if(n > 2) cnt ++;//2是質數 for(int i = 3; i < n; i +=2 ){ if(isPrime(i)) cnt ++; } return cnt; } };
這樣就通過了。
西元前250年,希臘數學家厄拉多塞(Eeatosthese)想到了一個非常美妙的質數篩法,減少了逐一檢查每個數的的步驟,可以比較簡單的從一大堆數字之中,篩選出質數來,這方法被稱作厄拉多塞篩法(Sieve of Eeatosthese)。
具體操作:先將 2~n 的各個數放入表中,然後在2的上面畫一個圓圈,然後劃去2的其他倍數;第一個既未畫圈又沒有被劃去的數是3,將它畫圈,再劃去3的其他倍數;現在既未畫圈又沒有被劃去的第一個數 是5,將它畫圈,並劃去5的其他倍數……依次類推,一直到所有小於或等於 n 的各數都畫了圈或劃去為止。這時,表中畫了圈的以及未劃去的那些數正好就是小於 n 的素數。
其實,當你要畫圈的素數的平方大於 n 時,那麼後面沒有劃去的數都是素數,就不用繼續判了。如下圖:
C++程式碼如下:
class Solution {
public:
/*厄拉多塞篩法*/
int countPrimes(int n) {
int cnt = 0;
bool *del = new bool[n];
//vector<int> del(n);
del[2] = false;
for(int i = 3; i < n; i ++){ // 2的倍數全部劃去,也就是將2的倍數全部標為合數,其他全部標誌為素數
if(i % 2 == 0)
del[i] = true;
else
del[i] = false;
}
for(int i = 3; i < n; i ++){
if(!del[i]){
if(i*i > n) break; // 當前素數的平方大於n,跳出迴圈
for(int j = i; i*j < n; j ++){
del[i*j] = true;
}
}
}
for(int i = 2; i < n; i ++){
if(!del[i]) cnt ++;
}
delete [] del;
return cnt;
}
};