用布尔值打破嵌套的 while 循环

1 投票
5 回答
505 浏览
提问于 2025-04-18 12:52

我的程序是用来寻找毕达哥拉斯三元组的,也就是满足 a^2 + b^2 = c^2a+b+c=1000 的一组数字。程序运行得很顺利,但它在运行的早期就找到了答案,所以我想要在所有的循环中提前退出。我尝试了一个简单的布尔方法,但不知道为什么我的循环在运行了一秒后就停止了。如果我去掉 exit = True 这一行,程序就能正常运行(但显然就无法提前退出了)。

另外,如果我用简单的 01 来检查这个问题,结果也是一样的。有没有人能告诉我为什么会这样?

i = 0
j = 0
k = 0
exit = False
while (i < 999 and exit == False):
    while (j < 999 and exit == False):
        while (k < 999 and exit == False):
            if i*i + j*j == k*k:                        
                if i + j + k == 1000:
                    exit = True
                    ii = i
                    jj = j
                    kk = k
            k += 1
        j += 1
        k = 1
    i += 1
    j = 1
i = 1
print('result: %d^2 + %d^2 = %d^2' % (ii, jj, kk))

5 个回答

0

为什么不直接用一种更符合Python风格的方法来解决这个问题呢:

[(a,b,c) for a,b,c in itertools.product(range(0,999), repeat=3) if (a**2 + b**2 == c**2) and (a + b + c == 1000)]
0

你已经被建议过如何重构代码,以避免一开始就需要中断循环。个人来说,我会使用生成器函数的方式,参考一下@pillmuncher的解决方案(如果你还在考虑使用循环的话)。

这里有一个例子,展示了如何在不使用布尔标志的情况下中断循环:

i = 1
while i < 999:
    j = 1
    while j < 999:
        k = 1
        while k < 999:
            if i*i + j*j == k*k and i + j + k == 1000:
                ii, jj, kk = i, j, k
            else:
                k += 1
                continue
            break
        else:
            j += 1
            continue
        break
    else:
        i += 1
        continue
    break
print('result: %d^2 + %d^2 = %d^2' % (ii, jj, kk))

或者,使用更简洁的 for ... in range(...) 循环(在Python 2中更好用的方式是 xrange):

for i in range(1, 999):
    for j in range(1, 999):
        for k in range(1, 999):
            if i*i + j*j == k*k and i + j + k == 1000:
                ii, jj, kk = i, j, k
            else:
                continue
            break
        else:
            continue
        break
    else:
        continue
    break
print('result: %d^2 + %d^2 = %d^2' % (ii, jj, kk))
1

函数是处理提前退出逻辑的好方法。我还把你的循环改成了使用 xrange() 这个内置函数,这样可以让你的代码看起来更简洁。

def triplet():
    for i in xrange(1000):
        for j in xrange(1000):
            for k in xrange(1000):
                if i*i + j*j == k*k:                    
                    if i + j + k == 1000:
                        return (i, j, k)

i, j, k = triplet()
print('result: %d^2 + %d^2 = %d^2' % (i, j, k))

需要注意的是,从这里开始,你可以进行一些优化。

  • 比如说,给定 ij 后,你只需要测试一个 k,也就是 k == 1000 - i - j
  • 再比如,如果你已经测试过 i == 1j == 2,那么就不需要再测试 i == 2j == 1,因为它们的结果是一样的。

另外,如果你想在循环中跳过 0,可以用 xrange(1, 1000)xrange() 让你可以指定一个开始和结束的位置。

2

把它变成一个生成器函数:

>>> def pythagorean_triangles(target):
...     for a in range(1, target):
...         for b in range(1, target):
...             for c in range(1, target):
...                 if a ** 2 + b ** 2 == c ** 2 and a + b + c == target:
...                     yield a, b, c
...
>>> triangles = pythagorean_triangles(1000)
>>> next(triangles)
(200, 375, 425)
2

你遇到的具体问题就是,你的代码实际上是符合你设定的标准,当

ii == 0
jj == 500
kk == 500

如果你不想要这个简单的解决方案,你应该在一开始就把值初始化为1(或者,更好的是,找到这个简单的机会,把重复的部分提取出来,只在一个地方设置,比如j = 1)。

撰写回答