[筛法]埃氏筛和欧拉筛

LeetCode No.1175

这里用的埃氏筛。因为做题很少刷到筛法相关,会忘,所以还是整理。

class Solution {
    public int numPrimeArrangements(int n) {
        final int mod = 1000000007;
        if (n == 1) {
            return 1;
        }
        // 转为求 1 到 n 有几个质数
        // 使用埃式筛法
        int count = 0;
        boolean[] isNotPrime = new boolean[n + 1];
        for (int i = 2; i <= n; i++) {
            if (!isNotPrime[i]) {
                count++;
                for (int j = 1; j*i <= n; j++) {
                    isNotPrime[j*i] = true;
                }
            }
        }
        long result = 1;
        for (int i = 2; i <= count; i++) {
            result = Math.floorMod(result * i, mod);
        }
        for (int i = 2; i <= n-count; i++) {
            result = Math.floorMod(result * i, mod);
        }
        return (int)result;
    }
}

埃氏筛

因为质数的倍数不为质数,且已知最小的质数为 2。则从 2 开始,对质数进行遍历,将当前质数的 n 倍数都进行标记,不带标记的则为质数,可继续参与遍历。

欧拉筛

埃氏筛存在重复标记的问题,如对质数 2 和 3 的倍数进行标记时,{6, 12, 18, 24 …} 都会被重复标记。

当给定的范围越大,则重复标记的情况越严重。

欧拉筛通过最小质数因子判断来结束逻辑。

1175 使用欧拉筛处理。

class Solution {
    public int numPrimeArrangements(int n) {
        final int mod = 1000000007;
        if (n == 1) {
            return 1;
        }
        // 转为求 1 到 n 有几个质数
        // 使用欧拉筛法
        int count = 0;
        boolean[] isNotPrime = new boolean[n + 1];
        int[] primeArray = new int[n];
        // 从最小质数 2 开始遍历
        for (int i = 2; i <= n; i++) {
            // 如果是质数,则加入质数队列
            if (!isNotPrime[i]) {
                primeArray[count++] = i;
            }
            // 当前数 i 和 质数队列里的质数依次相乘,产生的合数都不为质数
            for (int j = 0; j < n && i*primeArray[j] <= n; j++) {
                isNotPrime[i*primeArray[j]] = true;
                // 关键步骤,i 在质数队列中找到最小质数因子,停止
                if (i % primeArray[j] == 0) {
                    break;
                }
            }

        }
        long result = 1;
        for (int i = 2; i <= count; i++) {
            result = Math.floorMod(result * i, mod);
        }
        for (int i = 2; i <= n-count; i++) {
            result = Math.floorMod(result * i, mod);
        }
        return (int)result;
    }
}