【问题标题】:Finding largest prime number out of 600851475143?从 600851475143 中找出最大的素数?
【发布时间】:2013-02-23 03:05:26
【问题描述】:

我正在尝试解决来自http://projecteuler.net 的问题 3。但是,当我运行东西程序时,什么都没有打印出来。 我究竟做错了什么? 问题:600851475143这个数的最大质因数是多少?

public class project_3 
{
    public boolean prime(long x)   // if x is prime return true
    {
        boolean bool = false;

        for(long count=1L; count<x; count++)
        {
            if( x%count==0 )
            {
                bool = false;
                break;
            }
            else { bool = true; }
        }
        return bool;
    }

    public static void main(String[] args)
    {
        long ultprime = 0L;  // largest prime value
        project_3 object = new project_3();

        for(long x=1L; x <= 600851475143L; x++)
        {
            if( object.prime(x)==true )
            {
                ultprime = ((x>ultprime) ? x : ultprime);
            }
        }
        System.out.println(ultprime);
    }
}

【问题讨论】:

  • for(long x=1L; x&lt;=600851475143L;x++) - 嗯...这需要一段时间...
  • count=2L开头
  • 你应该在sqrt(number)上停止for-loop
  • 如果你正在寻找最大的,那么我会从相反的方向开始
  • @JasonSperske 不,你不知道。从 600851475143 开始倒数是非常低效的。

标签: java primes prime-factoring factors factorization


【解决方案1】:

不仅你的prime检查函数总是返回false;即使它运行正常,您的主循环也根本不会寻找输入数字的因子,而只是寻找小于或等于它的最大素数。在伪代码中,您的代码相当于:

foo(n):
    x := 0 ;
    foreach d from 1 to n step 1:
        if is_prime(d):          // always false
            x := d
    return x                     // always 0

is_prime(d):
    not( d % 1 == 0 )            // always false

但是您根本不需要这里的素数检查功能。下面通过trial division找到一个数的所有因数:

factors(n):
    fs := []
    d  := 2
    while ( d <= n/d ):
        if ( n % d == 0 ): { n := n/d ; fs := append(fs,d) }
        else:              { d := d+1 }
    if ( n > 1 ): { fs := append(fs, n) }
    return fs

对可除性的测试只进行到数字的平方根。发现的每个因子都从被分解的数字中除以,从而进一步减少了运行时间。有问题的数字的因式分解立即运行,只需要 1473 次迭代。

通过构造,所有找到的因子都保证是素数(这就是为什么不需要素数检查的原因)。以升序枚举可能的除数对于实现这一点至关重要1。升序也是最有效的,因为任何给定的数字都更有可能具有较小的素因数而不是较大的素数。枚举素数而不是赔率,虽然不是必需的,但如果你有一种有效的方法来获取这些素数来测试除法,那么效率会更高。

增加上述内容以找到最大因子是微不足道的:只需将append实现为

append(fs,d):
    return d

1因为对于被分解的原始数字的任何复合除数d,当我们达到d时,我们已经将它的质因数除以原始数,因此减少的数将没有共同的素因数,即d 不会将减少的数除以原始数。

【讨论】:

  • 对正确答案的不明原因投反对票是怎么回事?我看不出这个答案有什么问题。
  • 你的答案是最好的答案,但你错的地方是你显然希望人们理性和知情地投票。只需看看问题本身的哪个 cmets 获得了最多的选票......(cmets 不可能投反对票)。庞大的数字保证了神话、假设和迷信(参见阿特金的筛子)正在不可阻挡地传播,尽管已经发布了详细、准确的揭穿(正如你所知道的那样)。太多半知半解的人在传播他们听到但不完全理解的东西,没有任何尽职调查。
  • @DarthGizka 我猜就是这样。 :) WP 和 SO 都订阅“一人一票(可能是不知情的)投票”系统(当然有细微差别);因此,两者都不是关于创建策划的知识存储库,尽管我们喜欢假装它们是......我已经发布了大约20个像这个一样的冗余答案,我猜测(至少?);理想情况下应该只有一个——如果有的话,因为其他人也发布了它们。
【解决方案2】:

两件事:

1) 您从 1 而不是 2 开始 count。所有整数都可以被 1 整除。

2) 您正在针对相当大的 N 运行 O(n^2) 算法(或者至少在您确定点 #1 后您将是这样)。运行时间会很长。

【讨论】:

  • 向下滚动代码以查看“System.out.println(ultprime);”。但你的其他观点是有效的。
  • 实际上,编写的代码不是 O(n^2),因为 prime() 内的循环只运行一次(因为 count 从 1 开始)。
  • 修正,如果算法没有被破坏,那就是 O(n^2)
  • @SteveKuo 找到素数很好,但不是解决这类问题的好方法。要找到一个数的最大素因数,您必须对其进行因式分解(好吧,您不必必须,还有其他方法)。通过试除法进行的简单因式分解对于给定大小的数来说已经足够好了,即使它本身就是素数。
  • OP 运行“一个 O(n^2) 算法”,该算法(在修复第一个点后)计算最大的质因数给定数字的 - 只是不超过该数字的最大 素数
【解决方案3】:

Project Euler 的全部意义在于,寻找答案的最明显方法将花费很长时间来计算,以至于它们不值得运行。这样你就学会了寻找不那么明显、更有效的方法。

就它是否能够计算某个数字的最大素数而言,您的方法在技术上是正确的。您没有看到任何打印出来的原因是您的算法无法快速解决问题。

按照您的设计方式,大约需要 4,000,000 年才能完成。

如果您将 600851475143 号码替换为 20,它将能够很快完成。但是你有6000亿这个数字,所以没那么简单。

【讨论】:

  • 您的估计大约相差 400 万年 - 在(C#!)中大约 25 微秒内用奇数因子 600851475143 进行简单的试验除法,因为这个数字只有很小的因子。即使是刚好大于其平方根的两个素数的乘积 (775147 * 775153 = 600857522491)——这是通过试除法分解的最坏情况——也只需要 4 毫秒。与往常一样,欧拉距离成为任何类型的挑战还有几个数量级。 OP 没有选择错误的方法/算法,他们只是未能充分实施。
猜你喜欢
  • 1970-01-01
  • 2015-08-11
  • 1970-01-01
  • 1970-01-01
  • 2018-12-09
  • 1970-01-01
  • 2014-08-02
  • 2011-04-15
  • 1970-01-01
相关资源
最近更新 更多