【问题标题】:Interview question : What is the fastest way to generate prime number recursively? [closed]面试题:递归生成素数最快的方法是什么? [关闭]
【发布时间】:2011-05-31 21:43:56
【问题描述】:

质数的生成很简单,但是找到它并递归生成(质数)它的最快方法是什么?

这是我的解决方案。然而,这不是最好的方法。我认为它是 O(N*sqrt(N))。如果我错了,请纠正我。

    public static boolean isPrime(int n) {
        if (n < 2) {
            return false;
        } else if (n % 2 == 0 & n != 2) {
            return false;
        } else {
            return isPrime(n, (int) Math.sqrt(n));
        }
    }

    private static boolean isPrime(int n, int i) {
        if (i < 2) {
            return true;
        } else if (n % i == 0) {
            return false;
        } else {
            return isPrime(n, --i);
        }
    }

   public static void generatePrimes(int n){
       if(n < 2) {
            return ;
       } else if(isPrime(n)) {
            System.out.println(n);
       } 

       generatePrimes(--n);

   }

   public static void main(String[] args) {

        generatePrimes(200);
   }

【问题讨论】:

  • 您正在测试素数,而不是生成素数。
  • 如果你想生成最多 n 个素数,你可以使用 Eratosthenes 筛。
  • 不确定你的面试官是想要最好的睡眠时间,还是只是最好的时间,但你可以通过根本不将偶数发送到函数中来获得局部优化。只需检查 200 是否为偶数,减去 1,然后每次调用 generatePrimes(n-=2)。
  • 但这真的不会给你带来太多好处,因为你检查它是否甚至在 isPrime 方法中......但我只是说......你可以做一些持续的时间工作,然后削减您对 generatePrimes 函数的调用减半。
  • 这似乎是一个非常愚蠢的面试问题。

标签: java algorithm math primes


【解决方案1】:

你需要的是永远的筛子,这是递归素数测试器的代码,我认为它非常有效,因为它只需要测试素数,让我知道你的想法;)

顺便说一句,我不会尝试超过一个字节的任何内容,超过 100 个似乎需要一段时间。

public boolean isPrime(byte testNum)
{
    if ( testNum <= 1 )
        return false;
    for ( byte primeFactor = 2; primeFactor < testNum; primeFactor++ )
        if ( isPrime(primeFactor) )
            if ( testNum % primeFactor == 0 )
                return false;
    return true;
}

【讨论】:

  • 2? -- 3?2? -- 4?2? -- 5?2?3?2?4?2? -- 6?2? -- 7?2?3?2?4?2?5?2?3?2?4?2?6?2? -- 8?2? -- 9?2?3?2? -- 10?2? -- 11?2?3?2?4?2?5?2?3?2?4?2?6?2?7?2?3?2?4?2?5?2?3?2? 4?2?6?2?8?2?9?2?3?2?10?2? ——……这算不上快,更不用说最快了。 :)
  • 所以不,它根本没有效率。它非常效率低下。你做了大量的工作来节省一个微不足道的余数测试。这口井可能是我见过的效率最低的 impl。 :)
  • 这非常慢,我喜欢它。 ECPP 和 AKS 是多对数的,试除法是多项式的,这是指数的。你还能在哪里看到这样的差距?
  • 所以,它是isPrime n = n &gt; 1 &amp;&amp; []==[f | f &lt;- [2..n-1], isPrime f &amp;&amp; rem n f == 0]。 (当然,对isPrime f 的调用完全是多余的)。仍然是缓慢的冠军。
【解决方案2】:

对于递归,你应该使用memoization 来改进你的递归函数,这意味着如果你找到素数将它保存在数组中,并且在调用isPrime(n) 时首先检查数组中是否存在如果没有调用 isPrime(n , (int) Math.sqrt(n))。如果 isPrime(n,i) 返回 true,将其添加到素数列表,最好对数组进行排序以进行二进制搜索,在 C# 中有排序列表,并且二进制搜索操作 [制作 n 项列表需要 O(n log n) 并且搜索是 O(log(n))] 我不知道 java [但你可以实现它]。

编辑:您当前的方法是O(n sqrt(n)),但我的方法可以是相同的顺序!但性能更好,实际上顺序是O(n sqrt(n) / log (n) + n log(n/log(n))),并且因为 log(n) 比 n^Epsilon 小,所以最好说它是 O(n sqrt(n)),但正如你所见,它运行 log(n) 时间会更快。

另外最好是 i-2 而不是 i-- 并且在启动时进行一些额外的检查以更快地运行算法 2*log(n) 时间。

【讨论】:

  • 没有办法在O(n)中生成素数n。记忆在这里没有帮助。你描述的是一个很好的优化,但它不是记忆化,也不是O(n),它仍然是O(n*sqrt(n)),因为素数测试仍然是O(sqrt n)
  • @lVald,实际上我的方法平均是 O(n),(就像 Qsort 是 n log n)因为调用 IsPrime(n,i) 的次数是有限的,我认为它是恒定的因子(真的不,它不是恒定的,但例如 log log log log n 在当前 PC 中是恒定的),并且由于方法是 isPrime(n, i - 2),所以广泛使用记忆,所以检查概率数,除非是素数(1 /log n)
  • @lVald,我将编辑我的答案以说出更准确的时间。
  • IVlad 返回 :) 所以 10 分钟内会有答案 :)
  • @Saeed - 我真的不确定你在描述什么。你可以发布伪代码吗?我看不出sqrt(n) * log(n) 来自哪里。 @hilal - @Kyle S 已经给出了一个很好的答案。在谷歌上查找 Eratosthenes 的筛子。如果您设法将经典算法转换为递归实现,那么您将毫无问题地为筛子做这件事。筛子在O(n log log n) 中运行。
【解决方案3】:

首先,如果您想生成大的素数数(而不是测试整数的素数),那么 Pocklington's theorem 派上用场。如果您知道足够多的 p-1 素因子,则该定理允许对候选 p 进行快速素性检验。因此,以下方法是可能的:生成几个素数,计算它们乘积的合适倍数并使用波克林顿定理进行测试。如果您想找到较大的素数(例如,对于 RSA 密码系统),则必须递归地应用此方法来生成 p-1 的因数。

上面的描述缺少很多细节。但该方法已被深入分析。我认为这篇论文在发表时是最快的方法,尽管从那时起已经过去了一段时间,可能有人对其进行了改进。

P.米海莱斯库。 “在算术级数中使用搜索快速生成可证明的素数”,CRYPTO 会议论文集 94,计算机科学讲义,第 939 卷,Springer 1994,第 282-293 页。

【讨论】:

    【解决方案4】:

    在数学中,阿特金筛法是一种快速、现代的算法,用于查找直到指定整数的所有素数。

    Wikipedia article(包含伪代码)

    为了解决递归问题,也许Sieve of Eratosthenes 可以递归实现。这个page 可能会有所帮助,因为它似乎在讨论递归实现。

    【讨论】:

    • 但在问题中提到:找到它并递归生成(素数)它
    • 也许我的编辑解决了递归要求;我不确定。
    • 我刚刚再次对其进行了编辑,以包含指向 CMU 网站上可能有用的页面的链接。
    • +1 表示有趣的 CMU 链接,-1 表示建议 Atkin 的筛子(抱歉 :)) - 它的 理论上 复杂性可能更好,但很难正确实施( WP文章中的伪代码是伪造的,它在其讨论页上这么说)并且那些尝试过的人说(在这里,在SO上)所涉及的恒定因素使得正确的wheel-erized Sieve仍然更慢埃拉托色尼的,肯定是 32 位范围的数字。
    • @WillNess:同意。我不知道 Atkin-Bernstein 筛在实践中优于经过适当优化的 SoE 的 任何 数字范围。 primegen 在 $2^{32}$ 之外的表现非常糟糕,而且我不知道任何其他严肃的实现。 (Google 发现了很多玩具实现。)
    【解决方案5】:

    为什么是递归的?

    使用更好的素数生成算法,例如埃拉托色尼筛法,甚至更好的阿特金筛法。

    【讨论】:

    • 在问题中提到:找到它并递归地生成(素数)它
    猜你喜欢
    • 1970-01-01
    • 2017-04-11
    • 1970-01-01
    • 2020-06-22
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    相关资源
    最近更新 更多