我参与了codewars网站的python挑战。我遇到了以下挑战:
42的除数是:1,2,3,6,7,14,21,42。这些除数的平方是:1,4,9,36,49,196,441,1764。平方的总和除数是2500,即50 * 50,一个正方形!
给定两个整数m,n(1 <= m <= n)我们想要找到m和n之间的所有整数,其平方除数之和本身就是一个平方。 42就是这样的数字。
结果将是一个数组数组,每个子数组有两个元素,首先是平方除数为平方的数字,然后是平方除数的总和。
输出应为:
list_squared(1, 250) --> [[1, 1], [42, 2500], [246, 84100]]
list_squared(42, 250) --> [[42, 2500], [246, 84100]]
list_squared(250, 500) --> [[287, 84100]]
我已经编写了以下代码,其中包含两个附加功能:一个用于确定数字的所有因子,另一个用于检查数字是否为完美正方形。
def fact(m):
return [i for i in range(1,m+1) if m%i == 0]
def square_root(x):
ans = 0
while ans < x // 2 + 1:
ans = ans + 1
if ans*ans == x:
return ans
break;
return 0
def list_squared(m, n):
# your code
fac=[]
for i in range(m,n+1):
sq_sum = sum(list(map(lambda x: x**2,fact(i))))
if square_root(sq_sum) != 0:
fac.append([i,sq_sum])
return fac
这段代码给了我正确的结果,但是它太长了。我能够通过所有的测试结果,但它花了我大约6000毫秒。当我尝试提交代码时,Web提交返回该算法效率低下并且花费超过1200毫秒这是最大值。
如果有人能指出更好的算法,我将非常感激。
答案 0 :(得分:2)
您的代码有几种优化,但最大的优化是在ans*ans
大于x
时停止:
def square_root(x):
ans = 0
while True:
ans += 1
sqans = ans*ans
if sqans == x:
return ans
elif sqans > x:
return 0
while
中的条件可以删除,因为现在测试是在平方值上完成的。
通过该优化,我使用250, 500
情况从8秒降至0.07秒。
但这并不令人满意。通常,包含中断或返回条件的算法至少为O(n)
,即使您可以节省时间,复杂性也会过高。
只需检查圆角平方根的平方即可做得更好:
def square_root(x):
ans = int(x**0.5 + 0.5) # rounded just in case it goes below the actual value (float inaccuracy)
sqans = ans*ans
return 0 if sqans !=x else x
我将执行时间再加2(由Optimized way to find if a number is a perfect square确认)
除此之外(这不会加速那么多,但值得一提):
无需在map
中将list
转换为sum
:
sq_sum = sum(map(lambda x: x**2,fact(i)))
同样fact
可以避免循环到最大数量。循环到最大数字除以2并将最大数字添加到列表中是等效的。最大数量/ 2
def fact(m):
return [i for i in range(1,m//2+1) if m%i == 0] + [m]
最终编辑:由于fact
中使用的列表理解,这仍然很慢。我可以通过使用生成器来大幅缩短时间,并在其外部添加m*m
:
def sqfact(m):
return (i*i for i in range(1,m//2+1) if m%i == 0)
最终代码,现在运行得如此之快,我得到0秒。
def sqfact(m):
return (i*i for i in range(1,m//2+1) if m%i == 0)
def square_root(x):
ans = int(x**0.5 + 0.5)
return 0 if ans*ans !=x else x
def list_squared(m, n):
# your code
fac=[]
for i in range(m,n+1):
sq_sum = sum(sqfact(i)) + i*i # add i square outside
if square_root(sq_sum):
fac.append([i,sq_sum])
return fac
答案 1 :(得分:1)
我已经更新了效率非常低的事实函数。现在,不是迭代到m
的完整值来找到它的因素,我只是上升到sqrt(m)
。这极大地缩短了运行时间。这背后的逻辑是微不足道的,所以我没有详细说明。以下是适用于我的新代码。
def fact(m):
#determining the lower factors i.e., smaller than sqrt(m)
fac = [i for i in range(1, int(m**0.5) + 1) if m%i == 0]
#determining the higher factors i.e., larger than sqrt(m)
fac = fac + [m//i for i in range(1, int(m**0.5) + 1) if m%i == 0]
return sorted(list(set(fac))) #in order to get rid of duplicate factors