文章

试除法分解质因数

试除法分解质因数

初始版本

1
2
3
4
5
6
7
8
9
10
11
12
public List<Integer> getPrimeList(int num) {
    List<Integer> factors = new ArrayList<>();
    // 0,1不为质数,从2开始遍历
    for (int i = 2; i * i <= num; i++) {         // 优化点:只遍历到 sqrt(num)
        if (num % i == 0) {                      // 能整除,i 为 num 的因数
            factors.add(i);
            while (num % i == 0) num /= i;
        }
    }
    if (num > 1) factors.add(num);
    return factors;
}

从最小质数 2 开始遍历,并将 i 除尽,保证较大的合数被较小的质数分解。

例如:遍历到 4 时,此时 num 已没有因数 2,所以 num % 4 != 0 会跳过。

加一次列表,再试除,保证质因数列表不重复。

优化版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public List<Integer> getPrimeList(int num) {
    List<Integer> factors = new ArrayList<>();
    if (num < 2) return factors;
    // 特殊处理
    if (num % 2 == 0) {
        factors.add(2);
        while (num % 2 == 0) num /= 2;
    }

    // 步长为2,只遍历奇数
    for (int i = 3; i * i <= num; i += 2) {
        if (num % i == 0) {
            factors.add(i);
            while (num % i == 0) num /= i;
        }
    }

    if (num > 1) factors.add(num);
    return factors;
}

所有质数中只有 2 为偶数,先处理掉 2,接下来只遍历奇数。

预处理版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public List<Integer> getPrimeList(int num) {
    List<Integer> factors = new ArrayList<>();
    for (int prime = 2; prime < isPrime.length; prime++) {
        if (!isPrime[prime]) continue;
        if (prime * prime > num) break;
        if (num % prime == 0) {
            factors.add(prime);
            while (num % prime == 0) num /= prime;
        }
    }
    
    if (num > 1) factors.add(num);
    return factors;
}

通过质数筛预处理,可以看这篇博客:质数筛

假设已预处理得到一个 isPrime 数组,只需要遍历质数,判断是否为因数即可。

要点:isPrime 数组长度需要大于 num 开根。

本文由作者按照 CC BY 4.0 进行授权

热门标签