[英]How can I make this sum of perfect squares function more efficient?
我的部分作業涉及制作一個函數來檢查一個數字是否是兩個平方之和。 問題是較大的數字需要很長時間才能通過它。 關於如何提高效率的任何建議? 例如,給定數字50
它會返回(7,1)
因為 7^2 是 49 並且 1^2 是 1 所以總數是 50 這是代碼:
def sum_of_squares(n) :
i = 1
while i * i <= n :
j = 1
while(j * j <= n) :
while (i * i + j * j == n) :
return (j,i)
j = j + 1
i = i + 1
def sum_of_squares(n) :
range = round(math.sqrt(n))
i = 1
while i <= round(range/2) :
j = range;
while(j >= round(range/2)) :
while (i * i + j * j == n) :
return (j,i)
j = j - 1
i = i + 1
來自https://www.geeksforgeeks.org/check-whether-number-can-represented-sum-two-squares/的算法修改
方法一
該技術基本上是循環從 0 到 sqrt(n) 的數字,將平方 i * i 存儲為字典鍵,將 i 作為值。
如果數字 (n - i * i) 已經在字典中,那么你已經找到了一對 (i & d[n - i * i].
返回具有最大元組值的解決方案。
算法復雜度 O(sqrt(n))。
def sum_square(n):
d = {}
maxi = None
for i in range(n):
if i * i > n:
break
# store squared value with value in dictionary
d[i*i] = i # saving the square root of i*i as i
try:
k = d[n - i*i] # check if n- i*i is already in a key
if maxi:
maxi = max(maxi, (i, k)) # update max solution
else:
maxi = (i, k) # first solution
except:
continue
return maxi
方法二
def sum_square_binary(n):
def binary_search(start_, end_, val):
# If lower limit exceeds
# upper limit.
if start_ > end_:
return None
# Calculating mid.
mid = start_ + (end_ - start_) // 2
if mid * mid == val:
return mid
if mid * mid > val:
return binary_search(start_, mid - 1, val)
return binary_search(mid + 1, end_, val)
maxi = None
for i in range(n):
if i*i > n:
break
b = n - i * i
# Use binary search to see if b is a perfect square
# only need to check range [0, b] in binary search
k = binary_search(0, b, b) # k is the root of b (if perfect square)
if k:
maxi = max(maxi, (i, k), key = max) if maxi else (i, k)
return (max(maxi), min(maxi)) if maxi else maxi
方法三
import math
def sum_square_sqrt(n):
def integer_sqrt(x):
""" Returns sqrt of integer if it is a perfect square.
Uses technique from Cook https://www.johndcook.com/blog/2008/11/17/fast-way-to-test-whether-a-number-is-a-square/ to reduce the number of times sqrt is called """
# Find the floating point value of
# square root of x.
h = x & 0xF
if h > 9:
return None
if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ):
sr = math.sqrt(x)
# If square root is an integer
return int(sr) if ((sr - math.floor(sr)) == 0) else None
else:
return None
maxi = None
for i in range(n):
if i*i > n:
break
b = n - i * i
# Use binary search to see if b is a perfect square
# only need to check range [0, b] in binary search
k = integer_sqrt(b) # k is the root of b (if perfect square)
if k:
maxi = max(maxi, (i, k), key = max) if maxi else (i, k)
return (max(maxi), min(maxi)) if maxi else maxi
表現
使用字典的方法 1 要快得多,與方法 3 相當。 方法 3 應該沒問題,直到 sqrt 作為對較大 n 的測試變得不准確。
tst = [randint(1e6, 1e9) for _ in range(10)]
%timeit for k in tst: sum_square(k)
>>>方法 1:每個循環 180 ms ± 14.7 ms(7 次運行的平均值 ± 標准偏差,每個循環 1 次)
%timeit for k in tst: sum_square_binary(k)
>>>方法 2:每個循環 4.04 s ± 97.1 ms(7 次運行的平均值 ± 標准偏差,每個循環 1 次)
%timeit for k in tst: sum_square_sqrt(k)
>>>方法 3:每個循環 192 ms ± 5.66 ms(平均值 ± 標准偏差,7 次運行,每次 10 次循環)
您可以使用動態編程,以防止反復重新計算平方。 通過使用跟蹤結果列表,您可以只查找值。 如果該值還沒有定義,你只需計算一次,如果之前已經計算過,你只需返回列表中的相應條目,而不是重新計算:
squares = []
def get_square(x):
global squares
if(squares[x] == -1):
squares[x] = x * x
return squares[x]
def sum_of_squares(n):
global squares
squares = [-1 for i in range(n)]
i = 1
while get_square(i) <= n - 1:
j = 1
while(get_square(j) <= n - 1) :
if(get_square(i) + get_square(j) == n) :
return (j,i)
j = j + 1
i = i + 1
print(sum_of_squares(25))
正如上面其他人所建議的,在每次迭代中阻止計算平方是一個好的開始。 這是一個使用 for 循環的簡單實現:
def sum_of_squares(n):
lim = int(n**0.5)+1
for i in range(1, lim):
for j in range(1,i):
if(i**2 + j**2==n):
return (i,j)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.