【问题标题】:How to loop a number so that the number iterates through every possible value?如何循环一个数字,以便该数字遍历每个可能的值?
【发布时间】:2016-04-03 22:45:16
【问题描述】:

当我遇到问题时,我正在做 Project Euler 中的第 9 题。我的程序运行时间太长了。半个多小时。这是我的代码。

def Problem9():
    a = 1
    b = 1
    c = 1
    x = []
    while(a + b + c != 1000):
        a = a + 1
        for i in range(0,1000):
            c = 1000 - (a + b)
            if a < b < c:
                if (a*a) + (b*b) == (c*c):
                    x.append(a*b*c)
                    print(a*b*c)
            b = b + 1
    print(x)

Problem9()

这基本上应该找出所有加起来一千的毕达哥拉斯三元组(链接到问题以便您可以更好地理解它:https://projecteuler.net/problem=9)我的代码中有问题我可以修复还是我的代码根本错误?

【问题讨论】:

  • 循环结构看起来非常不自然和复杂。您应该有两个普通的嵌套for 循环,并设置其他两个变量中的第三个变量。优化退出条件,避免不必要的循环。

标签: python arrays loops


【解决方案1】:

既然您知道这三个数字之和必须等于1000a &lt; b &lt; c,您就可以利用这一事实更有效地(并且干净地)循环。

def Problem9():
    for a in range(1000):
        for b in range(a,1000):
            if a**2 + b**2 == (1000 - a - b)**2:
                return a*b*(1000 - a - b)

在这里,您将 a 从 1 循环到 1,000。由于 b 必须大于 a,因此您可以从 a 循环到 b 直到 1,000。然后,既然你知道1000 = a + b + c,然后是c = 1000 - a - b,你就可以测试你的毕达哥拉斯条件而无需更多的循环。

【讨论】:

  • 如果b &gt; a,第二个循环必须从a+1开始。
【解决方案2】:

毕达哥拉斯三元组是三个自然数的集合,a 其中 a2 + b2 = c2。 恰好存在一个毕达哥拉斯三元组,其 a + b + c = 1000。

这会起作用

def pythagorean_tiplet():
  a = 1
  while(a < 1000):
      b = a + 1 # note this, b is starting from a + 1, since b starting from 0 is useless and will only add to the running time.
      while (b < 1000):
        result = a**2 + b**2
        c = math.sqrt(result) 
        if (( a + b + c) == 1000 and (a < b < c)): #test for conditions
            return a * b * c
        b += 1
      a += 1


print(pythagorean_tiplet())

这个 算法绝对不适合周长 s > 1 000 000。 有一种更快的算法可以用来解决它。你可以搜索parametrisation of Pythagorean triplets

【讨论】:

    【解决方案3】:

    你有系统

    (*1) a + b + c = 1000
    (*2) a² + b² = c²
    

    如果

    a + b + c = 1000
    

    然后

    a + b = 1000 - c
    (a + b)² = (1000 - c)²
    a² + 2ab + b² = 1000² - 2000c + c²
    ( a² + b² ) + 2ab = 1000² - 2000c + c²
    

    但是,通过 (*2),( a² + b² ) = c²,然后

    c² + 2ab = 1000² - 2000c + c²
    2ab = 1000² - 2000c
    2000c = 1000² - 2ab
    

    然后

    c = 500 - ab/(1000)
    

    所以,现在,你有了新系统:

    (*3) a + b + 500 - ab/(1000) = 1000
    (*4) c = 500 - ab/(1000)
    

    另外,abc都是整数,a&lt;b&lt;c; 如果a&gt;332a 必须至少是 333,然后, b 至少应为 334,然后 c 应至少为 335333 + 334 + 335 = 1002.

    有了更多的数学,你可以更容易地做到这一点。


    def p():
        for a in range(1,333):
            for b in range(a+1,(1000-a)/2):
                if ( 1000*a + 1000*b + 500000 - a*b == 1000000 ):
                    c=500-((a*b)/1000)
                    print (a,b,c);print a*b*c
                    return
    p()
    

    结果:

    时间 python Special_Pythagorean_triplet.py

    (200, 375, 425) 31875000

    真实 0m0.041s 用户 0m0.036s sys 0m0.000s

    if 语句中:

    if ( 1000*a + 1000*b + 500000 - a*b == 1000000 )
    

    你可以使用:

    if ( a + b + 500 - (a*b)/1000 == 1000 )
    

    但是,在这种情况下,只有整数很重要: 使用第一个,您可以解决除法及其舍入问题。

    【讨论】:

    • 8 个空格缩进?为什么?
    【解决方案4】:

    更好的方法是使用 itertools

    https://docs.python.org/3.4/library/itertools.html

    from itertools import product
    def ff1():
        for r in product(range(1,1000),repeat=3):
            a,b,c=r
            if a+b+c==1000:
                if a<b<c:
                    if a**2+b**2==c**2:
                        print(a,b,c)
                        print(a*b*c)
    
    ff1()
    

    【讨论】:

      【解决方案5】:

      这段代码真的很尴尬。 while 条件本身是错误的,您将停止前 3 个总和为 1000 的数字,然后退出。另一个错误是 B 没有重置。您可以按照 Ibukun 的建议进行类似的操作,但这不是这种直接方法的最佳方法。您不需要检查它们的总和是否为 1000。这更简单:

      1. 将 A 从 3 迭代到 997
      2. 将 B 从 A+1 迭代到 999-A
      3. 做 C = 1000 - A - B(这就是你不需要检查总和的方式,你已经这样做了)
      4. 检查它们是否是三胞胎,当它们是三胞胎时,你就完成了!

      输入正确答案后,您可以查看其他很棒的方法,它们会更有趣

      【讨论】:

        猜你喜欢
        • 2014-06-29
        • 1970-01-01
        • 2019-03-15
        • 1970-01-01
        • 2019-09-02
        • 2012-07-07
        • 1970-01-01
        • 1970-01-01
        • 2012-08-16
        相关资源
        最近更新 更多