题解 | #筛法判断质数#

筛法判断质数

https://www.nowcoder.com/practice/8afab457ef11456d8602ce6dc30db776

题目链接

HIGH8 筛法判断质数

题目描述

给定 T 个正整数,对于每个正整数 x,请判断它是否为质数。

  • x 是质数,输出 "Yes"。
  • x 不是质数,输出 "No"。

【名词解释】质数(或素数):在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

解题思路

当需要对多个数进行质数判断时,为每个数单独使用试除法会很慢。一个更高效的策略是先预处理,用筛法一次性找出某个范围内的所有质数,然后对于每个查询,直接查表即可。埃拉托斯特尼筛法(Sieve of Eratosthenes)是实现这一目标的经典算法。

  1. 算法原理

    • 我们创建一个布尔数组 is_prime,大小为 N+1N 是题目中 x 的最大可能值,如 10^6),并初始化所有值为 true,表示我们假设所有数都是质数。
    • 我们知道 0 和 1 不是质数,所以手动将 is_prime[0]is_prime[1] 设为 false
    • 从第一个质数 2 开始遍历。如果一个数 p 仍然被标记为 true,那它就是一个质数。
    • 对于每个找到的质数 p,我们将它所有的倍数(2*p, 3*p, 4*p, ...)在数组中标记为 false,因为它们必然是合数。
  2. 优化

    • 在标记倍数时,我们可以从 p*p 开始。因为任何小于 p*pp 的倍数(例如 k*p 其中 k<p),必然有一个更小的质因子 k,所以在处理 k 时就已经被筛掉了。
    • 外层循环也只需要遍历到 sqrt(N) 即可,因为任何大于 sqrt(N) 的合数,其最小质因子必然小于 sqrt(N),所以它也一定被筛掉了。
  3. 回答查询

    • 筛法执行完毕后,is_prime 数组就成了一张完整的“质数表”。
    • 对于之后来的每一个查询 x,我们只需要检查 is_prime[x] 的值即可,这是一个 的操作。

代码

#include <iostream>
#include <vector>

using namespace std;

const int N_MAX = 1000001;
bool is_prime[N_MAX];

void sieve() {
    fill(is_prime, is_prime + N_MAX, true);
    is_prime[0] = is_prime[1] = false;
    for (int p = 2; p * p < N_MAX; ++p) {
        if (is_prime[p]) {
            for (int i = p * p; i < N_MAX; i += p) {
                is_prime[i] = false;
            }
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    sieve();

    int t;
    cin >> t;
    while (t--) {
        int x;
        cin >> x;
        if (is_prime[x]) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    }
    return 0;
}
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static final int N_MAX = 1000001;
    static boolean[] isPrime = new boolean[N_MAX];

    static {
        Arrays.fill(isPrime, true);
        isPrime[0] = isPrime[1] = false;
        for (int p = 2; p * p < N_MAX; p++) {
            if (isPrime[p]) {
                for (int i = p * p; i < N_MAX; i += p) {
                    isPrime[i] = false;
                }
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while (t-- > 0) {
            int x = sc.nextInt();
            if (isPrime[x]) {
                System.out.println("Yes");
            } else {
                System.out.println("No");
            }
        }
    }
}
N_MAX = 1000001
is_prime = [True] * N_MAX
is_prime[0] = is_prime[1] = False

# 埃拉托斯特尼筛法
p = 2
while p * p < N_MAX:
    if is_prime[p]:
        for i in range(p * p, N_MAX, p):
            is_prime[i] = False
    p += 1

# 读取输入并查询
t = int(input())
for _ in range(t):
    x = int(input())
    if is_prime[x]:
        print("Yes")
    else:
        print("No")

算法及复杂度

  • 算法:埃拉托斯特尼筛法
  • 时间复杂度:。筛法预处理的时间复杂度为 ,其中 N 是数据上限 (10^6)。之后的 T 次查询,每次都是 的查表操作。
  • 空间复杂度:。需要一个大小为 N 的布尔数组来存储质数表。
全部评论

相关推荐

07-09 18:28
门头沟学院 Java
写着提前批,结果还要实习4个月以上???
程序员牛肉:这种不用看,直接投了,面试的时候问对应的HR就行。有可能他们是直接复制的暑期实习的模板。
点赞 评论 收藏
分享
06-07 00:00
已编辑
腾讯_后端开发
点赞 评论 收藏
分享
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
今天 14:00
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务