1. 程式人生 > 實用技巧 >[知識點] 6.4.1 素數與最大公約數

[知識點] 6.4.1 素數與最大公約數

總目錄> 6 數學 > 6.4 數論 > 6.4.1 素數與最大公約數

前言

數論開始。這一塊知識點還挺凌亂的,又多又雜。

子目錄列表

6.4.1 素數與最大公約數

1、素數

對於正整數 a, d,如果存在正整數 k,使得 a = kd,則稱 d 整除 a,記作 d | a。這時,a 是 d 的倍數,而 d 是 a 的約數(因數,因子)。

顯然,對於任意大於 1 的整數 a,它都能被 1 和 a 整除,而如果它能且僅能被這兩個數整除,則稱 a 為素數(質數);否則,則稱 a 為合數。舉例子:

5 的約數為 1 和 5,則 5 為素數;

12 的約數為 1, 2, 3, 4, 6, 12,則 12 為合數。

1 既不是素數也不是合數。

順帶一提素數計數函式:小於等於 x 的素數的個數,用 π(x) 表示。當 x 趨近於無窮大時,π(x) 趨近於 x / lnx。

2、素數判定

判定 a 是否為素數,最暴力的做法是從 2 到 a - 1 逐一判斷看是否能整除,時間複雜度為 O(n),但其實是沒必要的,很容易發現,如果 d 是 a 的約數,則 a / d 也是 a 的約數,就如上述 12 的 6 個約數,可以組成 1 * 12, 2 * 6, 3 * 4 三組,而我們只需要對這些組較小的那個數進行判斷即可,顯然,這些較小數是恆小於等於 a 的平方根的。這樣,我們的時間複雜度驟降至 O(sqrt(n))。程式碼如下:

bool isPrime(int a) {
    for (int i = 2; i * i <= a; i++)
        if (a % i == 0) return 0;
      return 1;
}

同樣地,這個演算法可以延伸為求任意數的約數個數,此處略。

還有許多高大上的素數判定方法,諸如 Miller-Rabin 素性測試,Fermat 素性測試,卡邁克爾數等等概念,此處暫略。

3、反素數

① 概念

對於正整數 n,如果任何小於它的正整數的因子個數都小於它的因子個數,則稱 n 為反素數,比如 1, 2, 4, 6, 12, ...

為什麼這樣定義呢?因為素數可以認為是因子最少的數,反素數則是對於一個特定集合的因子最多的數,而這個特定集合就是 1 到這個數本身。

② 求解

如何求解反素數?要求一個數的因子個數,首先需要分解質因子,即把 n 分解成 n = p1 ^ k1 + p2 ^ k2 + ... + pn ^ kn 的形式,其中 p 為素數,k 為對應 p 的指數,這樣 n 的因子個數為 (k1 + 1) * (k2 + 1) * ... * (kn + 1)。並且,容易得到以下兩個推論:

> 假設 p1 < p2 < ... < pn,那麼 p1, p2, ..., pn 肯定是從 2 開始的連續素數數列;

> 假設 p1 < p2 < ... < pn,那麼肯定滿足 k1 >= k2 >= ... >= kn。

兩個推論均可通過反證法證明。

根據這兩個推論進行列舉就行啦。

程式碼:

本文參考了:

https://zhuanlan.zhihu.com/p/41759808