LeetCode 数学问题(上篇)

98 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第25天,点击查看活动详情

素数分解

每一个数都可以分解成素数的乘积,例如 84 = 22 * 31 * 50 * 71 * 110 * 130 * 170 * …

整除

令 x = 2m0 * 3m1 * 5m2 * 7m3 * 11m4 * …

令 y = 2n0 * 3n1 * 5n2 * 7n3 * 11n4 * …

如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。

最大公约数最小公倍数

x 和 y 的最大公约数为:gcd(x,y) = 2min(m0,n0) * 3min(m1,n1) * 5min(m2,n2) * ...

x 和 y 的最小公倍数为:lcm(x,y) = 2max(m0,n0) * 3max(m1,n1) * 5max(m2,n2) * ...

1. 生成素数序列

  1. Count Primes / 计数质数 (Easy)

小于非负整数n的质数个数

Leetcode / 力扣

题解:

方法1:埃氏筛法

埃拉托斯特尼筛法在每次找到一个素数时,将能被素数整除的数排除掉。需要注意的是,此题求的是小于n的质数

class Solution {
public:
    int countPrimes(int n) {
        int cnt = 0;
        vector<bool> st(n, false);

        for (int i = 2; i < n; i ++ ) { // <n
            if (st[i]) continue;
            cnt++;
            for (int j = i + i; j < n; j += i) // 筛掉倍数
                st[j] = true;
        }
        return cnt;
    }
};

有一点可以优化:j 从 i * i 开始筛,因为如果 k < i,那么 k * i 在之前就已经被筛过了

class Solution {
public:
    int countPrimes(int n) {
        int cnt = 0;
        vector<bool> st(n, false);
​
        for (int i = 2; i < n; i ++ ) { // <n
            if (st[i]) continue;
            cnt++;
            // j 从 i * i 开始筛,因为如果 k < i,那么 k * i 在之前就已经被筛过了
            for (long j = (long)i * i; j < n; j += i) // 筛掉倍数
                st[j] = true;
        }
        return cnt;
    }
};

还有一点可以优化:就像素数判定的优化一样,外层循环中 i 可以只枚举到 sqrt(i),但是个数的统计需要单独循环

class Solution {
public:
    int countPrimes(int n) {
        n -= 1; // 小于n的质数个数,转换为小于等于n-1的质数个数
        vector<bool> st(n, false);
​
        for (int i = 2; i <= n / i; i++) { // i*i < n
            if (st[i]) continue;
            for (long j = (long)i * i; j <= n; j += i) // 筛掉倍数
                st[j] = true;
        }
​
        int cnt = 0;
        for (int i = 2; i <= n; i++) // 统计质数个数
            if(!st[i]) cnt++;
​
        return cnt;
    }
};

方法2:线性筛法,更适用于求所有素数,而不仅仅是求素数个数

class Solution {
public:
    int countPrimes(int n) {
        vector<int> primes(n, 0);
        vector<bool> st(n, false);
        int cnt = 0;
​
        for (int i = 2; i < n; i++) { // <n
            if (!st[i]) primes[cnt++] = i;
            for (int j = 0; primes[j] <= n / i; j++) {
                st[primes[j] * i] = true;
                if (i % primes[j] == 0) break; // primes[j]一定是i的最小质因子
            }
        }
        return cnt;
    }
};