经典算法实例讲解:质数排列(二)

质数判断 + 组合数学

思路与算法

求符合条件的方案数,使得所有质数都放在质数索引上,所有合数放在合数索引上,质数放置和合数放置是相互独立的,总的方案数即为「所有质数都放在质数索引上的方案数」×「所有合数都放在合数索引上的方案数」。

求「所有质数都放在质数索引上的方案数」,即求质数个数 numPrimes 的阶乘。「所有合数都放在合数索引上的方案数」同理。

求质数个数时,可以使用试除法。「204.计数质数的官方题解」列举了更多的求质数个数方法,读者可以根据兴趣阅读。最后注意计算过程中需要对 10*9 + 7 取模。

代码

Python3

复制代码
class Solution:
    def numPrimeArrangements(self, n: int) -> int:
        numPrimes = sum(self.isPrime(i) for i in range(1, n + 1))
        return self.factorial(numPrimes) * self.factorial(n - numPrimes) % (10 ** 9 + 7)

    def isPrime(self, n: int) -> int:
        if n == 1:
            return 0
        for i in range(2, int(sqrt(n)) + 1):
            if n % i == 0:
                return 0
        return 1

    def factorial(self, n: int) -> int:
        res = 1
        for i in range(1, n + 1):
            res *= i
            res %= (10 ** 9 + 7)
        return res

C++

复制代码
const int MOD = 1e9 + 7;

class Solution {
public:
    int numPrimeArrangements(int n) {
        int numPrimes = 0;
        for (int i = 1; i <= n; i++) {
            if (isPrime(i)) {
                numPrimes++;
            }
        }
        return (int) (factorial(numPrimes) * factorial(n - numPrimes) % MOD);
    }

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

    long factorial(int n) {
        long res = 1;
        for (int i = 1; i <= n; i++) {
            res *= i;
            res %= MOD;
        }
        return res;
    }
};

C#

复制代码
public class Solution {
    const int MOD = 1000000007;

    public int NumPrimeArrangements(int n) {
        int numPrimes = 0;
        for (int i = 1; i <= n; i++) {
            if (IsPrime(i)) {
                numPrimes++;
            }
        }
        return (int) (Factorial(numPrimes) * Factorial(n - numPrimes) % MOD);
    }

    public bool IsPrime(int n) {
        if (n == 1) {
            return false;
        }
        for (int i = 2; i * i <= n; i++) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }

    public long Factorial(int n) {
        long res = 1;
        for (int i = 1; i <= n; i++) {
            res *= i;
            res %= MOD;
        }
        return res;
    }
}

复杂度分析

时间复杂度:O(n*3/2 ) 。求 n 个数中质数个数的时间复杂度为 O(n*3/2 ) ,阶乘的时间复杂度为 O(n) ,总的时间复杂度为 O(n*3/2) 。

空间复杂度:O(1) ,只使用了常数空间。