双正方形:计算两个完美正方形之和的数字

时间:2011-01-11 11:09:23

标签: algorithm math

来源:Facebook Hacker Cup Qualification Round 2011

双平方数是整数X,可以表示为两个正方形的总和。例如,10是双平方,因为10 = 3 2 + 1 2 。给定X,我们如何确定它可以写成两个方格之和的方式?例如,10只能写为3 2 + 1 2 (我们不算1 2 + 3 2 < / sup>作为不同的)。另一方面,25可写为5 2 + 0 2 或4 2 + 3 2

你需要解决这个问题,因为0≤X≤2,147,483,647。

示例:

  • 10 =&gt; 1
  • 25 =&gt; 2
  • 3 =&gt; 0
  • 0 =&gt; 1
  • 1 =&gt; 1

7 个答案:

答案 0 :(得分:7)

将数字n计算,并检查它是否具有奇数估值的素数因子p,使得p = 3(mod 4)。当且仅当n不是两个正方形的总和时才会这样做。

解决方案的数量具有封闭形式表达式,涉及n的除数。请参阅this, Theorem 3以获取准确的陈述。

答案 1 :(得分:6)

以下是O(sqrt(n))复杂性

中的简单答案
x^2 + y^2 = n
x^2 = n-y^2 
x = sqrt(n - y^2)

x应该是整数,因此(n-y^2)应该是完美的正方形。循环到y=[0, sqrt(n)]并检查(n-y^2)是否为完美正方形

伪代码

count = 0;
for y in range(0, sqrt(n))
    if( isPerfectSquare(n - y^2))
         count++
return count/2

答案 2 :(得分:3)

这是一个更简单的解决方案:

create list of squares in the given range (that's 46340 values for the example given)

for each square value x
  if list contains a value y such that x + y = target value (i.e. does [target - x] exist in list)
    output √x, √y as solution (roots can be stored in a std::map lookup created in the first step)

答案 3 :(得分:1)

考虑到X上的约束,遍历所有对(a,b)是不可行的。虽然有更快的方法!

对于固定的a,我们可以计算出b:b =√(X - a 2 )。 b虽然不会总是一个整数,所以我们必须检查一下。由于精度问题,请以小容差执行检查:如果b是x.99999,我们可以确定它是一个整数。因此,我们遍历a的所有可能值并计算b为整数的所有情况。我们需要注意不要重复计算,因此我们将约束放在&lt; = b。对于X = a 2 + b 2 ,在此约束条件下,a最多为√(X / 2)。

以下是C ++中此算法的实现:

int count = 0;
// add EPS to avoid flooring x.99999 to x
for (int a = 0; a <= sqrt(X/2) + EPS; a++) {
    int b2 = X - a*a; // b^2
    int b = (int) (sqrt(b2) + EPS);
    if (abs(b - sqrt(b2)) < EPS) // check b is an integer
        count++;
}
cout << count << endl;

See it on ideone with sample input

答案 4 :(得分:1)

这是一个简单的O(sqrt(N))版本,避免了所有循环内部分支。

首先生成所有直到极限的方块,轻松完成而不进行任何乘法,然后初始化l和r索引。

在每次迭代中,您计算​​总和,然后根据与目标值的比较更新两个指数和计数。这是sqrt(N)次迭代,用于生成搜索循环的表和最大sqrt(N)次迭代。使用合理的编译器估计的运行时间是每平方(N)最多10个时钟周期,因此对于最大输入值,如果2 ^ 31(sqrt(N)〜= 46341),这应该对应于少于500K个时钟周期或十分之几第二个:

unsigned countPairs(unsigned n)
{
    unsigned sq = 0, i;
    unsigned square[65536];

    for (i = 0; sq <= n; i++) {
        square[i] = sq;
        sq += i+i+1;
    }

    unsigned l = 0, r = i-1, count = 0;

    do {
        unsigned sum = square[l] + square[r];
        l += sum <= n;       // Increment l if the sum is <= N
        count += sum == n;   // Increment the count if a match
        r -= sum >= n;       // Decrement r if the sum is >= N
    } while (l <= r);
    return count;
}

一个好的编译器可以注意到最后的三个比较都使用相同的操作数,因此它只需要一个CMP操作码,然后是三个不同的条件移动操作(CMOVcc)。

答案 5 :(得分:0)

我很着急,所以使用Python 2.6使用相当强力的方法(非常类似于marcog)来解决它。

def is_perfect_square(x):
    rt = int(math.sqrt(x))
    return rt*rt == x

def double_sqaures(n):
    rng = int(math.sqrt(n))
    ways = 0
    for i in xrange(rng+1):
        if is_perfect_square(n - i*i):
            ways +=1
    if ways % 2 == 0:
        ways = ways // 2
    else:
        ways = ways // 2 + 1
    return ways

注意:当数字是完美的平方时,ways将是奇数。

答案 6 :(得分:-1)

的解(x,y)的数量

的x ^ 2 + Y ^ 2 = N

整数上的

正好是n一致到1 mod 4的除数的4倍。 对于问题也存在类似的身份

x ^ 2 + 2y ^ 2 = n

x ^ 2 + y ^ 2 + z ^ 2 + w ^ 2 = n。