Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使这个完美平方和函数更有效?_Python_Python 3.x_Function_While Loop - Fatal编程技术网

Python 如何使这个完美平方和函数更有效?

Python 如何使这个完美平方和函数更有效?,python,python-3.x,function,while-loop,Python,Python 3.x,Function,While Loop,我家庭作业的一部分是做一个函数,检查一个数字是否是两个平方的和。问题是,大量的数据需要很长时间才能通过它。有没有关于如何提高效率的建议?例如,给定数字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 *

我家庭作业的一部分是做一个函数,检查一个数字是否是两个平方的和。问题是,大量的数据需要很长时间才能通过它。有没有关于如何提高效率的建议?例如,给定数字
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平方和(n):
i=1
而i*i
def平方和(n):
范围=四舍五入(数学sqrt(n))
i=1
而i=圆形(范围/2)):
而(i*i+j*j==n):
返回(j,i)
j=j-1
i=i+1

您可以使用动态编程,以防止反复计算正方形。通过跟踪结果列表,您只需查找值即可。如果尚未定义该值,则只需计算一次,如果之前已计算过,则只需返回列表中的相应条目,而不是重新计算:

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))
squares=[]
def get_平方(x):
全球广场
如果(平方[x]=-1):
正方形[x]=x*x
返回方块[x]
定义平方和(n):
全球广场
平方=[-1表示范围内的i(n)]
i=1

而得到_平方(i)算法的一种改进

  • 方法1——将方块保存在字典中,以便以后查找
  • 方法2——使用二进制搜索计算整数平方根
  • 方法3——使用 math.sqrt函数
  • 方法1

    该技术基本上是通过从0到sqrt(n)的数字循环,将平方i*i存储为字典键,i作为值

    如果数字(n-i*i)已经在字典中,那么您已经找到一对(i&d[n-i*i])

    返回具有最大元组值的解决方案

    算法复杂度O(sqrt(n))

    方法2

    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
    
    方法3

    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次)

    >>方法2:4.04 s±97.1 ms/循环(7次运行的平均值±标准偏差,每个循环1次)


    方法3:每个循环192 ms±5.66 ms(7次循环的平均值±标准偏差,每个循环10次)

    如上所述,防止每次迭代中计算平方是一个良好的开端。下面是一个使用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)
    

    有很多优化技术可以提到,这导致这个问题变得有点不确定。对不起,对于python来说,这是一个相当新的问题,可以提到什么样的优化技术?我想到了记忆。也许还可以使用
    sqrt
    floor
    ?一种更好的方法来查看代码的哪些部分实际需要优化的是使用
    timeit
    或其他类型的profiling,您可以消除所有乘法。平方序列只是奇数整数的累积和,因为
    (i+1)**2==i**2+2*i+1
    。在Python 3.8中,
    [平方:=(square+i)表示范围(1,n,2)]
    ,或者在Python的任何最新版本中,
    列表(itertools.acculate(范围(1,n,2),operator.add))
    大家好,欢迎来到stackoverflow!如果您详细介绍一下您的解决方案,您的帖子将对OP更有意义。仅仅给出纯代码有点超出stackoverflow的范围。乘法非常便宜;哈希表查找要昂贵得多。需要是
    dict
    ,这样您就可以返回
    n-i*i@o11c--我作弊并返回了两个正方形。我想我会把它变成一个dict并返回两个实际的数字。@o11c--谢谢,更新为使用字典来返回对而不是正方形。@DarrylG这是可行的,但我的函数要求是它希望返回的方式能够最大化较大的数字。例如integer 50,我希望它返回(7,1)而不是(5,5)@piethon——更新后它返回最大元组——因此在本例中返回(7,1)50。你的
    lim
    方法实际上比原来的方法更糟糕。你减少
    j
    的迭代次数减少了常数因子,但它仍然是二次复杂度。
    tst = [randint(1e6, 1e9) for _ in range(10)]
    
    %timeit for k in tst: sum_square(k)
    
    %timeit for k in tst: sum_square_binary(k)
    
    %timeit for k in tst: sum_square_sqrt(k)
    
    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)