{x}
blog image

Prime Arrangements

Return the number of permutations of 1 to n so that prime numbers are at prime indices (1-indexed.)

(Recall that an integer is prime if and only if it is greater than 1, and cannot be written as a product of two positive integers both smaller than it.)

Since the answer may be large, return the answer modulo 10^9 + 7.

 

Example 1:

Input: n = 5
Output: 12
Explanation: For example [1,2,5,4,3] is a valid permutation, but [5,2,3,4,1] is not because the prime number 5 is at index 1.

Example 2:

Input: n = 100
Output: 682289015

 

Constraints:

  • 1 <= n <= 100

Solution Explanation for Prime Arrangements

This problem asks us to find the number of permutations of numbers from 1 to n such that prime numbers are placed at prime indices. The solution leverages mathematical principles and efficient prime number counting.

Core Idea:

  1. Count Primes: First, we need to determine how many prime numbers exist between 1 and n (inclusive). We'll use the Sieve of Eratosthenes for efficient prime counting.

  2. Factorial Calculation: The number of ways to arrange p prime numbers in p prime indices is p! (p factorial). Similarly, the number of ways to arrange n-p non-prime numbers in n-p non-prime indices is (n-p)!. The total number of valid permutations is the product of these two factorials: p! * (n-p)!.

  3. Modulo Operation: Since the result can be very large, we need to apply the modulo operation (10^9 + 7) throughout the calculation to prevent integer overflow.

Time Complexity Analysis:

  • Sieve of Eratosthenes: The Sieve of Eratosthenes has a time complexity of O(n log log n), which is very efficient for finding primes up to n.

  • Factorial Calculation: Calculating the factorial of a number involves a loop iterating up to that number, resulting in O(n) time complexity. However, the largest factorial we compute is at most n!, so this remains a linear time complexity component.

Overall Time Complexity: O(n log log n) (dominated by the Sieve of Eratosthenes)

Space Complexity: O(n) (due to the boolean array used in the Sieve of Eratosthenes)

Code Implementation (Python):

def numPrimeArrangements(n: int) -> int:
    def count_primes(n):
        primes = [True] * (n + 1)
        primes[0] = primes[1] = False  # 0 and 1 are not prime
        for i in range(2, int(n**0.5) + 1):
            if primes[i]:
                for j in range(i * i, n + 1, i):
                    primes[j] = False
        return sum(primes)
 
    def factorial(n, mod):
        result = 1
        for i in range(1, n + 1):
            result = (result * i) % mod
        return result
 
    mod = 10**9 + 7
    num_primes = count_primes(n)
    return (factorial(num_primes, mod) * factorial(n - num_primes, mod)) % mod
 

Code Implementation (Java):

class Solution {
    private static final int MOD = (int) 1e9 + 7;
 
    public int numPrimeArrangements(int n) {
        int numPrimes = countPrimes(n);
        return (int) ((factorial(numPrimes) * factorial(n - numPrimes)) % MOD);
    }
 
    private int countPrimes(int n) {
        boolean[] isPrime = new boolean[n + 1];
        Arrays.fill(isPrime, true);
        isPrime[0] = isPrime[1] = false;
        for (int i = 2; i * i <= n; i++) {
            if (isPrime[i]) {
                for (int j = i * i; j <= n; j += i) {
                    isPrime[j] = false;
                }
            }
        }
        int count = 0;
        for (boolean b : isPrime) {
            if (b) count++;
        }
        return count;
    }
 
    private long factorial(int n) {
        long res = 1;
        for (int i = 2; i <= n; i++) {
            res = (res * i) % MOD;
        }
        return res;
    }
}

The Java and other language implementations follow a similar structure, adapting the core logic to their syntax and standard libraries. The key is the efficient prime counting using the Sieve and the careful handling of large numbers through modulo arithmetic.