線性篩法求質數
阿新 • • 發佈:2020-10-07
數尋找時,開始最普遍的思路就是雙重迴圈暴力列舉,時間複雜度O(N),複雜度通常比較高,最可怕的是當資料範圍特別大的時候(1e),於是就需要像尤拉篩O(N)與埃氏篩O(nloglog)這樣的演算法。
埃氏篩法
又稱為Eratosthenes篩法(埃拉託斯特尼),簡單來講就是找到一個質數x,然後成倍2x,4x,6x......這樣來進行查詢,找到一個數就標記,沒標記的肯定是質數。
埃氏篩法的基本思想 :一般從2開始,將每個質數的倍數標記成合數,以達到篩選質數的目的。
1 #include <bits/stdc++.h> 2 using namespace std; 3 bool prime[100005]; 4 int n; 5 void primes(int n){ 6 for(int i = 2; i <= n; i++) if(!prime[i]){ 7 cout << i << " "; 8 for(int j = 2 * i; j <= n; j += i)prime[j] = true; 9 } 10 } 11 int main(){ 12 cin >> n; 13 primes(n); 14 return 0; 15 }
發現2和3都對6進行了更新.所以我們可以進行優化,第二層迴圈的下限改成一下。
for(int j = i; j <= n / i; j++){ prime[i * j] = true; }
埃氏篩法缺陷:對於一個合數,有可能被篩多次。例如10=110=25那麼如何確保每個合數只被篩選一次?我們只要用它的最小質因子來篩選即可。
尤拉篩法
這個演算法建立在埃氏篩法之上,用它的最小質因子來篩選,可以達到不重複的目的。
當x、y不互質時,若x是y的最小質因數,則e(xy)=e(y)+1。
#include <bits/stdc++.h> #define maxn 100000 int s[maxn],prime[maxn],i,j,cnt; //初始化素數 void Prime(){ for(i = 2;i<=maxn;i++) { if(!s[i]) prime[++cnt] = i;//記錄素數個數 for(j = 1; j <= cnt && i*prime[j] <= maxn; j++){ s[i*prime[j]] = 1; if(i % prime[j] == 0) break; } } }
保證每個數只被篩選一次:if(i % prime[j] == 0)break;// 保證了一個數只被篩一次。
這條語句保證了,每一個合數都只被篩除一次。為什麼呢?由於 i % prime[i] == 0 ,那麼如果繼續篩下去,i * prime[j+1]一定也會是某一個合數,那麼如果下一次判斷這個合數的時候,它依然會被prime[j] 篩掉.
雖然尤拉篩快,但複雜度高,容易RE。