如何使此代码更有效地应对编码挑战?

时间:2019-05-05 12:00:28

标签: python

我正在进行名为Integers:Codewars中的Recreation One的编码挑战。

挑战=>给定两个整数m,n(1 <= m <= n),我们想找到m和n之间的所有整数,它们的平方除数之和本身就是一个正方形。

def list_squared(m, n):
    lst = list()
    for num in range(m, n+1):
        total= 0
        for i in range(1, num//2 +1):
            if num % i == 0:
                total += i**2
        total += num**2

        if (total**(1/2)) % 1 == 0:
            lst.append([num, total])

    return lst

我的代码适用于示例测试,但是当我尝试提交它时,它给我“执行超时”错误。我认为我必须提高效率,但不知道该怎么做。如何使代码更高效?

1 个答案:

答案 0 :(得分:0)

sqrt想法的实现:

def list_squared(m, n):
    lst = list()
    for num in range(m, n+1):
        total = 0
        sqrt = int(math.sqrt(num))
        for i in range(1, sqrt+1):
            q,r=divmod(num,i)
            if r == 0:
                total += i*i + q*q
        if sqrt*sqrt == num:
            total -= num

        if math.sqrt(total) % 1 == 0:
            lst.append([num, total])

    return lst

似乎可行。可能不正确的几件事:

  • 我不知道**(1/2)math.sqrt的效果是否更好,可以对其进行检查。但是我觉得sqrt更具可读性。当然,如果不允许使用数学库,请坚持使用**
  • x*x可能比x**2更快,也可以对其进行检查
  • 在汇编级别,商和余数是一步生成的,这对于Python可能是正确的,也可能不是正确的。但是,这就是为什么我使用divmod(所以q*q替换了(num/i)*(num/i)(num/i)**2的原因)

实际上,这些细节可能根本不重要,缩短内循环应该是主要技巧。


@ H.E.K .:您“觉得”可以通过/2来以某种方式缩短循环,但是实际上它必须是平方根。
如果inum的除数,则num/i也是num的除数。并且,如果i1开始增加,则num/inum/1开始减少(因此也从num本身开始减少)。随着时间的流逝,他们将在某个地方碰面,那就是sqrt(num)。将i增加到sqrt(num)以上会导致检查您已经看到的除数对。 带有20:

的示例
i   20/i
1   20
2   10
3   <something fraction>
4   5    <--- this is the last step when we encounter a new divisor
5   4    <--- here the divisors are "old", we have seen 4 and 5 already
6   <something fraction>
......

因此除数为1,20,2,10,4,5-我们不必分别检查5 ... 20,就足以检查1...4=(int)sqrt(20),这是一个很大的收益。