Java中的素数 - 算法

时间:2013-07-21 10:30:24

标签: java algorithm math primes

我已经开始学习用Java编写代码并决定使用Project Euler网站给我一些小任务来尝试完成我学习的每一段新编码。所以我遇到了Problem 3

13195的主要因素是5,7,13和29。 600851475143的最大主要因素是什么?

我想到了这个问题并研究了许多关于素数的不同理论,以及如何通过各种不同的计算找到它们(以Eratosthenes的筛子为例),我想到的解决方案是测试2 - >的数字。 n并查看它们是否为素数,如果它们是那么我将Tn变量(在本例中为600851475143)除以新发现的素数并查看它是否是一个因子。如果是,我会将它分配给变量Hp(最高素数),在程序结束时我会将Hp输出到控制台以给出我的结果。

这是我的代码:

public class Largest_Prime_Factor_NEW_SOLUTION {

    static long Tn = 600851475143L;
    static long Hp = 0;
    static boolean isPrime = false;

    public static void main(String[] args) {

        for (long i=2; i<Tn; i++) {
            System.out.println("TESTING NUMBER " + i);
            for (long k=2; k < i; k++) {
                if (i % k == 0) {
                    System.out.println(i + " IS NOT A PRIME");
                    break;
                } else if (k + 1 == i) {
                    isPrime = true;
                }
            }

            if (isPrime) {
            System.out.println(i + " IS A PRIME");
            if (Tn % i == 0) {
                System.out.println(Tn + " IS DIVISIBLE BY " + i);
                Hp = i;
            } else {
                System.out.println(Tn + " IS NOT DIVISIBLE BY " + i);
            }
            }

            isPrime = false;
        }
        System.out.println("THE HIGHEST PRIME NUMBER OF " + Tn + " IS " + Hp);
    }
}

现在我知道这段代码非常低效,而且刚开始我已经设法从我开始的地方压缩它(到处都有循环!)但是我要问的是,我该如何改进呢?它惹恼了我,因为我所研究的一切都与其他人的做法相矛盾,而且非常令人困惑。我已经尝试了筛选方法,但我知道布尔数组只能是一个int数组,而不是一个长数组?

据我所知,在开始编码时,我将仅限于可以使用的知识,但只是出于兴趣,我很想知道最终的解决方案是什么。

6 个答案:

答案 0 :(得分:7)

你可以做的是找到Tn的最低除数。假设它是p,再次找到Tn/p的最低除数,依此类推。

现在,每一步p都是素数[下面的解释]。所以收集它们,它们是Tn的主要除数。

为了更好的时间复杂度,您可以检查最多只有ceil(sqrt(Tn))的除数,而不是Tn-1

当您开始检查Tn的素数除数时,您可以从2开始。一旦你得到一个素数除数p,就不要再从2开始Tn/p。因为Tn/p也是Tn的除数,因为Tn的除数不小于pTn/p也没有。p。因此,再次从p开始[Tn可以在p]中拥有多个权力。如果Tn未划分p+1,请转到{{1}}。

示例:

Tn = 45
1.从2开始.2不分45 2.下一个测试是针对3. 45可以被3整除。所以3是它的主要除数 3.现在检查45/3 = 15的素数除数,但从3开始,而不是从2开始。 好吧,15可以被3整除。所以从15/3 = 5开始 5.注意5,ceil(sqrt(5))是3.但是5不能被3整除。但是因为4>小区(SQRT(5)) 我们可以毫无疑问地说5是素数。

因此45的主要除数是3和5。


为什么数字的最小除数(1除外)是素数?

假设上述陈述是错误的。那么数字N具有最小但复合的除数,比如C。

所以C | N. 现在C是复合的,它的除数小于自身但大于1 比如说C的这个除数是P.
所以P | C,但我们有C | N =&gt; P | N,其中1 < P&lt; C.

这与我们的假设相矛盾,即C是N的最小除数,所以一个数的最小除数总是一个素数。

答案 1 :(得分:1)

感谢您的帮助,在阅读完评论和答案之后,我设法将代码进一步压缩到以下内容:

    public class Largest_Prime_Factor_NEW_SOLUTION_2 {

    static long Tn = 600851475143L;

    public static void main(String[] args) {

        for (long i = 2; i < Math.sqrt(Tn); i++) {

            if(Tn % i == 0) {
                Tn = Tn / i;
                i--;
            }   
        }
        System.out.println(Tn);
    }
}

它完美无缺!再次感谢您的帮助和时间来帮助我理解。我知道这更像是一个数学问题,而不是编码问题,但它帮助我理解了一些事情。我现在要去学习别的东西了:))

答案 2 :(得分:0)

有很多方法可以改进这样的程序,但改进主要是用数学而不是编程:

  • 在查找因素时,请检查每个数字,而不仅仅是素数。如果你找到一个因素检查它是否是素数。你可以通过这种方式节省许多素数。

  • 复合数的最大素数因子最多可以是数字的平方根,因此您可以提前停止迭代。

  • 使用快速素性测试而不是进行试验分割http://en.wikipedia.org/wiki/Primality_test

然后,这是一次性的。不要过度复杂化。

答案 3 :(得分:0)

由于您正在将此作为一项学习练习,当您对当前课程进行了充分的改进时,为什么不尝试以不同的方式解决同一问题? Fermat Factorization Method首先找到大的因素。

答案 4 :(得分:0)

通过试验除法对复合数进行分解的简单算法如下:

function factors(n)
    f, fs := 2, []
    while f * f <= n
        while n % f == 0
            fs.append(f)
            n := n / f
        f := f + 1
    if n > 1
        fs.append(n)
    return fs

该算法可以改进,并且有更好的算法来分解大数,但它足以完成您的任务。当您准备好了更多时,我在我的博客中谦虚地推荐essay 使用Prime数字编程,其中包括该算法的实现以及Java中的其他实现。

答案 5 :(得分:0)

这是this的java版本:

 static boolean isPrime(int n){
    if (n == 2) return true;
    if (n == 3) return true;
    if (n % 2 == 0) return false;
    if (n % 3 == 0) return false;

    int i = 5;
    int w = 2;
    while (i * i <= n) {
        if(n % i == 0)
        return false;

        i += w;
        w = 6 - w;
    }
    return true;
}

正如@Alexandru描述的那样:它是经典O(sqrt(N))算法的变体。它使用了这样一个事实:素数(除了2和3)的形式是6k-1和6k + 1,并且只看这种形式的除数。