我正在进行名为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
我的代码适用于示例测试,但是当我尝试提交它时,它给我“执行超时”错误。我认为我必须提高效率,但不知道该怎么做。如何使代码更高效?
答案 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
更快,也可以对其进行检查divmod
(所以q*q
替换了(num/i)*(num/i)
或(num/i)**2
的原因)实际上,这些细节可能根本不重要,缩短内循环应该是主要技巧。
/2
来以某种方式缩短循环,但是实际上它必须是平方根。i
是num
的除数,则num/i
也是num
的除数。并且,如果i
从1
开始增加,则num/i
从num/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)
,这是一个很大的收益。