我可以更快地制作关于EulerProblem的代码吗?

时间:2012-02-18 10:42:26

标签: java performance algorithm

我编写了一个必须找到EulerProblem解决方案的程序。我想训练我的程序技能,这就是我注册欧拉的原因。

这是问题所在:

毕达哥拉斯三元组是一组三个自然数,a< b< c,为此, a ^ 2 + b ^ 2 = c ^ 2

例如,3 ^ 2 + 4 ^ 2 = 9 + 16 = 25 = 5 ^ 2.

恰好存在一个毕达哥拉斯三重态,其中a + b + c = 1000。 找到产品abc。

这是我的代码,但它运行缓慢,需要几个小时才能给我正确的abc。

static int findTriplet(int getal)
{
    boolean test = false;
    for(int a = 1; !test; a++)
        for(int b = a+1; !test; b++)
            for(int c = b+1; !test; c++)
            {
                if( a*a + b*b == c*c)
                {
                    if(a+b+c == getal)
                    {
                        return (a*b*c);
                    }
                }

            }
    return 0;
}

是否可以使代码更快或者是否正常需要数小时?

亲切的问候,

编辑:

感谢您的帮助。 !test boolean对此没用,这很有效:

static int findTriplet(int getal)
{
    for(int a = 1; a < 1000; a++)
        for(int b = a+1; b < 1000; b++)
            for(int c = b+1; c < 1000; c++)
            {
                if( a*a + b*b == c*c)
                {
                    if(a+b+c == getal)
                    {
                        return (a*b*c);
                    }
                }

            }
    return 0;
}

我还写了一个haskell变体也可以做到这一点。

认为这在Haskell中更容易,效率更高。

获取提示。

3 个答案:

答案 0 :(得分:5)

为了优化这种天真的算法,您首先要了解:

  1. 您的实际源代码根本不会停止。只要测试为false,它就会运行。您还冒险遇到c的溢出。
  2. 尝试a,b和c的每种可能组合将导致尝试1000 * 999 * 988 = 997 002 000次(!)。
  3. 此算法的关键点是:
    • 在循环中停止条件
    • 找到下一个尝试的方法
    • 尽可能减少循环的方法
  4. 现在,你知道你需要:

    1. 使用您的问题条件找到避免第三个循环的方法
    2. 找到使用问题条件更聪明地增加a和b的方法
    3. 使用您的问题条件找到更早停止循环的方法
    4. 以下是一些易于优化的提示:

      • as amit&amp; sirko说,如果你已经知道 a b ,你可以猜测 c
      • 每次检查新b时都不需要重新计算* a
      • 您不需要检查直到&lt; 1000和b < 999,组合的可能性要小得多

      一些更难以优化的提示:

      • 您不需要每次都重新计算b * b
      • 您不需要浏览所有可能的组合

答案 1 :(得分:1)

最后for是多余的,您可以找到c = sqrt(a^2 + b^2),这会使您的算法更快。

实际上,您只需检查c [自然数]中是否N sqrt(a^2 + b^2) = c,并检查a+b+c == 1000是否

此优化将使您的解决方案O(n^2)取代O(n^3),速度提高1000倍!

编辑:正如评论中所述:

  1. 然后检查c = sqrt(a^2 + b^2)c = 1000 - a -b可能会有更快的解决方案,但重要的部分是在O(n^2)而不是O(n^3)中执行此操作。
  2. 这个答案更像是一个指导方针,然后是一个完整的答案。关于循环的停止条件还有很多工作要做。这个答案的目的只是为了让你了解如何更快地完成它。

答案 2 :(得分:0)

看一个高而薄的直角三角形,基部为a,高度为b,斜边为c。 第一个ab总是少于cc = sqrt(a*a+b*b),所以正如其他海报所说的那样,您只需要搜索a和{{1} }}。 您也知道b因此,查看小型a+b >= c对没有意义。

现在,假设您从a,b开始,那么a=0, b=500,总周长为1000。 现在,您将c==500增加1并计算周长。它将超过1000。 然后将a减1.然后周长将小于1000。 然后将b增加1,直到周长>再次1000。

因此,只要周长<= 1000,就增加a。 只要它是> 1000,减少a。 如果它等于1000,你有一个答案。然后继续。

只要b

,您只需执行此操作

此算法应为a<b,因为它不会浪费时间用于小对。

然后你所要做的就是向自己证明它不会错过任何答案。 你可以通过假设它确实错过了一个有效的O(N)答案,并证明这是不可能的。