如何高效尋找素數

2022-07-03 23:00:12 字數 2575 閱讀 4328

素數的定義看起來很簡單,如果乙個數如果只能被 1 和它本身整除,那麼這個數就是素數。

// 返回區間 [2, n) 中有幾個素數 

int countprimes(int n)

// 比如 countprimes(10) 返回 4

// 因為 2,3,5,7 是素數

int countprimes(int n) 

// 判斷整數 n 是否是素數

boolean isprime(int n)

這樣寫的話時間複雜度 o(n^2),問題很大。首先你用 isprime 函式來輔助的思路就不夠高效;而且就算你要用 isprime 函式,這樣寫演算法也是存在計算冗餘的

先來簡單說下如果你要判斷乙個數是不是素數,應該如何寫演算法。只需稍微修改一下上面的 isprim **中的 for 迴圈條件:

boolean isprime(int n)
換句話說,i不需要遍歷到n,而只需要到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]也一定不會發現可整除因子。

現在,isprime函式的時間複雜度降為 o(sqrt(n)),但是我們實現countprimes函式其實並不需要這個函式,以上只是希望讀者明白sqrt(n)的含義,因為等會還會用到。

高效解決這個問題的核心思路是和上面的常規思路反著來:

首先從 2 開始,我們知道 2 是乙個素數,那麼 2 × 2 = 4, 3 × 2 = 6, 4 × 2 = 8... 都不可能是素數了。

然後我們發現 3 也是素數,那麼 3 × 2 = 6, 3 × 3 = 9, 3 × 4 = 12... 也都不可能是素數了。

看到這裡,你是否有點明白這個排除法的邏輯了呢?先看我們的第一版**:

int countprimes(int n)
如果上面這段**你能夠理解,那麼你已經掌握了整體思路,但是還有兩個細微的地方可以優化。

首先,回想剛才判斷乙個數是否是素數的isprime函式,由於因子的對稱性,其中的 for 迴圈只需要遍歷[2,sqrt(n)]就夠了。這裡也是類似的,我們外層的 for 迴圈也只需要遍歷到sqrt(n)

for (int i = 2; i * i < n; i++) 

if (isprim[i])

...

除此之外,很難注意到內層的 for 迴圈也可以優化。我們之前的做法是:

for (int j = 2 * i; j < n; j += i) 

isprim[j] = false;

這樣可以把i的整數倍都標記為false,但是仍然存在計算冗餘。

比如n = 25i = 4時演算法會標記 4 × 2 = 8,4 × 3 = 12 等等數字,但是這兩個數字已經被i = 2i = 3的 2 × 4 和 3 × 4 標記了。

我們可以稍微優化一下,讓ji的平方開始遍歷,而不是從2 * i開始:

for (int j = i * i; j < n; j += i) 

isprim[j] = false;

這樣,素數計數的演算法就高效實現了,其實這個演算法有乙個名字,叫做 sieve of eratosthenes。看下完整的最終**:

int countprimes(int n)
該演算法的時間複雜度比較難算,顯然時間跟這兩個巢狀的 for 迴圈有關,其運算元應該是:

n/2 + n/3 + n/5 + n/7 + ...

= n × (1/2 + 1/3 + 1/5 + 1/7...)

括號中是素數的倒數。其最終結果是 o(n * loglogn),有興趣的讀者可以查一下該演算法的時間複雜度證明。

以上就是素數演算法相關的全部內容。怎麼樣,是不是看似簡單的問題卻有不少細節可以打磨呀?

如何高效尋找素數

如果 個數如果只能被 1 和它本 整除,那麼這個數就是素數。返回區間 2,n 中,素數的個數 int countprimes int n 時間複雜度o n 2 int countprimes int n 判斷整數n是否是素數 boolean isprime int n return true 找其他...

尋找素數對

哥德 猜想大家都知道一點吧.我們現在不是想證明這個結論,而是想在程式語言內部能夠表示的數集中,任意取出乙個偶數,來尋找兩個素數,使得其和等於該偶數.做好了這件實事,就能說明這個猜想是成立的.由於可以有不同的素數對來表示同乙個偶數,所以專門要求所尋找的素數對是兩個值最相近的.input 輸入中是一些偶...

尋找素數對

哥德 猜想大家都知道一點吧.我們現在不是想證明這個結論,而是想在程式語言內部能夠表示的數集中,任意取出乙個偶數,來尋找兩個素數,使得其和等於該偶數.做好了這件實事,就能說明這個猜想是成立的.由於可以有不同的素數對來表示同乙個偶數,所以專門要求所尋找的素數對是兩個值最相近的.輸入中是一些偶整數m 5對...