簡體   English   中英

我怎樣才能使這個完美平方和函數更有效?

[英]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/的算法修改

  1. 方法1--將正方形保存在字典中供以后查找
  2. 方法2--使用二分查找計算整數平方根
  3. 方法 3--使用 math.sqrt 函數檢查數字是否為完全平方數

方法一

該技術基本上是循環從 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM