歐拉篩素數法和埃拉託斯特尼篩法篩法(歐拉篩和埃式篩)
由於對算法的學習比較吃力,所以爭取就是一點一點的理解算法,一句一註釋,將每一個存在的疑問都寫下來,致力於:方便像我這樣的小白快速學算法!
- 首先,學習算法之前,先了解一些基礎的知識:
- 素數(質數):如果一個大於1的自然數,如果只能被 1 和它本身整除,那麼這個數就是素數。
- 合數:自然數中除了能被1和本身整除外,還能被其他數(0除外)整除的數。
- 自然數1,既不是質數,又不是合數
- 算數定理:任何一個合數(非質數),都可以以唯一的形式被寫成有限個質數的乘積,即分解質因數
-
埃式篩
- 算法思想:如果一個數是素數,那麼它的倍數一定不是素數。我們要找
n
以內的所有素數,那麼把n
以內的合數全部篩掉,剩下的就是素數了。 - 算法代碼如下:
/** *找n以內的所有素數的個數 * */ int countPrimes(int n){ vector<bool> isPrim(n,true); //定義n大小的數組,賦默認值true for(int i = 2;i < sqrt(n);++i){ //遍歷所有的數,遍歷到開方即可 if(isPrim[i]) //避免冗餘 for(int j = i*i; j < n; j+=i){ isPrim[j] = false; //排除掉非質數,即把小於n的所有的i的倍數篩掉 } } int counter= 0 ; for(int i = 2; i < n;++i){ if(isPrim[i]){ ++counter; //計數,true爲素數,false爲合數 } } return counter; }
-
算法釋疑
- 爲什麼篩選到
sqrt(n)
引用力扣的一個例子,如下:
後兩個乘積就是前面兩個反過來,反轉臨界點就在
sqrt(n)
。所以兩層的for循環,只需要其中一層可以遍歷
sqrt(n)——n
之間的數即可。12 = 2 × 6 12 = 3 × 4 12 = sqrt(12) × sqrt(12) 12 = 4 × 3 12 = 6 × 2
- 爲什麼
j = i*i
開始
試想以下,如果 j = i * ( i - 1) ,那麼, ( i - 1) < i , ( i - 1) 一定已經被篩選過了
- 爲什麼
j+=i
正如前面所說,篩選掉素數的整數倍數,即篩選掉小於 n 的 i ,i+1 ,i+2 …倍的自然數
- 爲什麼篩選到
-
時間複雜度:
O(n * log (log n) )
-
缺陷
正如上面的式子
例如:對素數2進行篩選時,已經將自然數 6 篩選掉了; 但是到了對素數3處理時, 再一次篩選掉自然數6,對於這種情況,要想解決,所以就有了歐拉篩。
- 算法思想:如果一個數是素數,那麼它的倍數一定不是素數。我們要找
-
歐拉篩
- 算法思想:將合數分解爲一個最小質數乘以另一個數的形式,即
合數 = 最小質數 * 自然數
,然後通過最小質數來判斷當前數是否被標記過。 - 算法代碼如下:
/** *找n以內的所有素數的個數 * */ int countPrimes(int n){ //歐拉篩選法 vector<int>isPrim(n,0); //記錄得到的素數,默認值爲0 vector<bool>status(n,true); //記錄該值的狀態,默認值爲true int cnt = 2; for(int i = 2 ; i < n; ++i){ //遍歷所有的數 if(status[i]) isPrim[cnt++] = i; //存放所有的素數 for(int j = 2; (j < cnt)&&(i * isPrim[j] < n);++j){ //cnt表示素數數組中的個數 status[i * isPrim[j]] = false; //篩去合數 if(i % isPrim[j] == 0) break; //表示已經篩選過了 } } int counter= 0 ; for(int i = 2; i < n;++i){ if(isPrim[i]){ ++counter; //計數,true爲素數,false爲合數 } } return counter; }
-
算法釋疑
- 爲什麼
isPrim[cnt++] = i
運行第一遍時,先將最小質數2,存入數組進行篩選
以後再次執行該語句時,符合判斷條件的值,將存入素數數組中
- 爲什麼
if(i % isPrim[j] == 0) break;
可以這樣理解:
在素數數組中的值,已經全部篩選過了,並且是遞增的
如果取餘之後爲0,則表明找到了該值的最小質因數
當i=21,prime[j]=3時,63被篩掉
而 i=9,prime[j]=7時則不會,因爲i=9時,這個循環中,循環到prime[j]=3時,就會break出來,根本不會再繼續,故這種情況根本不會出現
總結:一個合數被分解爲最小質因數*自然數,以最小質因數進行篩選
- 爲什麼
- 算法思想:將合數分解爲一個最小質數乘以另一個數的形式,即
-
時間複雜度:
O(n)
-
參考文章
。◕‿◕。