【问题标题】:Finding two consecutive primes such that the gap between them is greater than or equal to N找到两个连续的素数,使得它们之间的间隔大于或等于 N
【发布时间】:2021-11-27 07:07:18
【问题描述】:

我正在编写一个程序来读取整数 n (0 = n。

我的代码可以运行,但对于较大的 n,它会运行大约 10 秒。

#include <stdio.h>
#include <stdlib.h>

int isPrimeRecursive(int x, int i){
    if (x <= 2){
        return (x == 2 ? 1:0);
    }
    if (x % i == 0){
        return 0;
    }
    
    if (i * i > x){
        return 1;
    }
    return isPrimeRecursive(x, i+1);
}

int findSuccessivePrime(int x){
    while (1){
        x++;
        if (isPrimeRecursive(x, 2)){
            return x;
        }
    }
    return 0;
}

int findGoodGap(int n, int *arr){
    int prime = findSuccessivePrime(n*n);
    
    while (1){
        int gap;
        int succPrime;
        succPrime = findSuccessivePrime(prime);
        gap = succPrime - prime;
        if (gap >= n){
            arr[0] = succPrime;
            arr[1] = prime;
            return gap;
        }
        prime = succPrime;
    }
    return 0;
}

int main(int argc, char *argv[]){
    int n;
    int arr[2];
    scanf("%d", &n);
    int goodGap;
    goodGap = findGoodGap(n, arr);
    
    printf("%d-%d=%d\n", arr[0], arr[1], goodGap);
    
    return 0;
}

如何让程序更有效率?我只能使用 stdio.h 和 stdlib.h。

【问题讨论】:

  • 您查找主号码的功能不是很有效,而且您调用了很多次。一个适当的素数筛算法可能是有用的,以及在所谓的“竞争”或“在线评判”网站上常见的另一件事(你的问题有这样一个网站的味道):动态编程,这实际上只是先前计算值的缓存。
  • 只是一个小评论(我不太确定):如果你找到两个大于 N 的不同质数,它们不应该大于平方(N)吗?
  • 在处理素数时,从不编写isPrime() 方法。使用 Eratosthenes 筛及其各种改进或更好的算法(如果有),一次生成所有感兴趣的素数。
  • Module primes-generator 具有您需要的所有逻辑。而且由于是 JavaScript,转换成 C++ 应该非常简单。

标签: c primes


【解决方案1】:

算法效率很低。你一遍又一遍地重新计算相同的东西。你可以这样做:

int n;
// Input n somehow
int *p = malloc(n * sizeof *p);

for(int i=0; i<n; i++) p[i] = 1; // Start with assumption that all numbers are primes

p[0]=p[1]=0; // 0 and 1 are not primes

for(int i=2; i<n; i++) 
    for(int j=i*2; j<n; j+=i) p[j] = 0;

现在,p[i] 可以被视为判断 i 是否为素数的布尔值。

以上可以进一步优化。例如,当您已经删除了所有可被 2 整除的数字时,删除所有可被 4 整除的数字是毫无意义的。这是一个非常简单的 mod:

for(int i=2; i<n; i++) {
    while(i<n && !p[i]) i++; // Fast forward to next prime

    for(int j=i*2; j<n; j+=i) p[j] = 0;
}

正如 cmets 中提到的 Yom B,这是一种 memozation pattern,您可以在其中存储结果以供以后使用,这样我们就不必重新计算所有内容。但是dynamic programming 更进一步,这基本上意味着将 memozation 作为算法本身的一部分。

在 C64 演示场景中大量使用的纯 memozation 示例是预先计算三角函数的值表。甚至使用简单的乘法表,因为 C64 处理器的乘法比简单的查找要慢得多。一个缺点是更高的内存使用率,这是旧机器上的一个大问题。

【讨论】:

  • 这是一个记忆模式:en.wikipedia.org/wiki/Memoization
  • @YomB 更好。它是动态编程,您不仅可以缓存结果,还可以重用它们来计算缓存的其余部分。
【解决方案2】:

我认为找到所有质数并将其存储在一个数组中是一个好方法;在这种情况下,您不需要从头开始进行除法来确定一个数字是否是素数

这是通过除法检查数字“n”是否为素数的算法

bool isPrime(int n) {
    if(n <= 1) return false;
    if(n < 4) return true;
    if(n % 2 == 0) return false;
    if(n < 9) return true;
    if(n % 3 == 0) return false;

    int counter = 1;
    int limit = 0;
    while(limit * limit <= n) {
        limit = limit * 6;
        if(n % (limit + 1) == 0) return false;
        if(n % (limit - 1) == 0) return false;
    }

    return true;
}

如果你使用上面的算法,它的时间复杂度是 sqrt(n) 的顺序,你的整体时间复杂度会超过 n^2

我建议您使用“埃拉托色尼筛法”算法将素数存储在数组中

查看此链接 https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

这里是代码。我在 Main 函数中使用了优化的筛子。

#include <iostream>
using namespace std;

void Sieve(bool* list, const int n);
void OptimizedSieve(bool* list, const int n);

int main() {
    bool list[100 / 2];
    for(int i = 0; i < 100 / 2; i++) list[i] = true;
    OptimizedSieve(list, 100 / 2);

    for(int i = 0; i < 100 / 2; i++){
        if(list[i]) cout << (2 * i) + 1 << endl;
    }
    return 0;
}

void Sieve(bool* list, const int n){
    list[0] = false;
    list[1] = false;

    for(int p = 2; p * p <= n; p++){
        if(!list[p]) continue;
        for(int j = p * p; j < n; j += p){
            if(list[j] == true) list[j] = false;
        }
    }
}

void OptimizedSieve(bool* list, const int n){
    list[0] = false;
    for(int p = 3; p * p <= n; p += 2){
        if(!list[(2 * p) + 1]) continue;
        for(int j = p * p; j <= n; j += 2 * p){
            int index = (j - 1) / 2;
            if(list[index]) list[index] = false;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 2019-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    相关资源
    最近更新 更多