【问题标题】:Algorithm for expressing given number as a sum of two squares将给定数字表示为两个平方和的算法
【发布时间】:2020-12-14 05:58:23
【问题描述】:

我的问题如下:

给定一个自然数 n,我想找到所有自然数 x 和 y,这样

n = x² + y²

由于这是加法顺序无关紧要,因此我将 (x,y) 和 (y,x) 视为一种解决方案。

我的初始算法是假设 y>x,对于所有 x 计算 y²=n-x² 并使用对 y² 的二进制搜索来检查 y 是否为自然数。


for(x=1;2*x*x<n;x++)
{
     y_squared=n-x*x;
     if(isSquare(y_squared)==false)
           continue;

     //rest of the code
}

我的算法有什么改进吗?我已经检查了 n 是否可以使用两个平方定理得到解决方案,但我想知道有多少。

我的算法是 O(sqrt(n) * log(n) )

提前致谢。

【问题讨论】:

    标签: algorithm optimization mathematical-optimization


    【解决方案1】:

    你可以这样减少到O(sqrt(n))

    all_solutions(n):
        x = 0
        y = floor(sqrt(n))
    
        while x <= y
            if x * x + y * y < n
                x++
            else if x * x + y * y > n
                y--
            else
                // found a match
                print(x, y)
                x++
                y--
    

    此算法将查找并打印所有可能的解决方案,并且将始终终止 x &lt;= sqrt(n / 2)y &gt;= sqrt(n / 2),导致最多执行 sqrt(n / 2) + (sqrt(n) - sqrt(n / 2)) = sqrt(n) 迭代。

    【讨论】:

    • x 和 y 从 sqrt(n) 开始,每次迭代距离至少缩小 1,所以最多也是 sqrt(n) 次迭代。
    • @KellyBundy 好吧,不完全是。如果您要获取精确值,上限实际上是sqrt(2) sqrt(n)。还是你的意思是O(sqrt(n))
    • 你从哪里得到额外的 sqrt(2)?
    • @KellyBundy 我们需要将xy sqrt(n / 2) 分别递减/递减,所以总共有2 * sqrt(n / 2) = 2 * sqrt(n) / sqrt(2) = sqrt(2) * sqrt(n) 操作。
    • 更明确地说,您从 distance = y - x = floor(sqrt(n)) - 0 = floor(sqrt(n)) 开始。然后你像while distance &gt;= 0:一样循环,并且在每次迭代中将distance减少1或2。因此最多floor(sqrt(n))迭代。
    【解决方案2】:

    Paul's 的变体,跟踪平方和并仅通过加法/减法对其进行调整:

    伪代码:(从左到右计算 x++ + xy-- + y,或者像下面的 Python 代码一样)

    x = 0
    y = floor(sqrt(n))
    sum = y * y
    
    while x <= y
        if sum < n
            sum += x++ + x
        else if sum > n
            sum -= y-- + y
        else
            print(x, y)
            sum += 2 * (++x - y--)
    

    Java:

      static void allSolutions(int n) {
        int x = 0, y = (int) Math.sqrt(n), sum = y * y;
        while (x <= y) {
          if (sum < n) {
            sum += x++ + x;
          } else if (sum > n) {
            sum -= y-- + y;
          } else {
            System.out.println(x + " " + y);
            sum += 2 * (++x - y--);
          }
        }
      }
    

    Python:

    from math import isqrt
    
    def all_solutions(n):
        x = 0
        y = isqrt(n)
        sum = y ** 2
    
        while x <= y:
            if sum < n:
                x += 1
                sum += 2 * x - 1
            elif sum > n:
                sum -= 2 * y - 1
                y -= 1
            else:
                # found a match
                print(x, y)
                x += 1
                sum += 2 * (x - y)
                y -= 1
    

    演示:

    >>> all_solutions(5525)
    7 74
    14 73
    22 71
    25 70
    41 62
    50 55
    

    【讨论】:

    • 跟踪x * x + y * y 形成的值的好主意。不过,我会让增量/减量步骤远离算术的其余部分,特别是因为您使用的是x++ + x == 2 * x + 1。在评估顺序方面,这些东西可能会变得非常混乱。
    • @Paul 是的,这就是我使用 Java 的原因,我认为可以保证从左到右。然后我把它变成了伪代码,它不是。希望人们只会做“正常”的事情并从左到右阅读,或者自己思考一下:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    相关资源
    最近更新 更多