对于给定的非负整数 c,需要判断是否存在整数 a 和 b,使得 a^2 + b^2 = c。可以枚举 a 和 b 所有可能的情况,时间复杂度为 O(c^2)。但是暴力枚举有一些情况是没有必要的。例如:当 c = 20 时,当 a = 1 的时候,枚举 b 的时候,只需要枚举到 b = 5 就可以结束了,这是因为 1^2 + 5^2 = 25 > 20。当 b > 5 时,一定有 1^2 + b^2 > 20。
注意到这一点,可以使用 sqrt 函数或者双指针降低时间复杂度。
方法一:使用 sqrt 函数
在枚举 a 的同时,使用 sqrt 函数找出 b。注意:本题 c 的取值范围在 [0,2^{31} - 1],因此在计算的过程中可能会发生 int 型溢出的情况,需要使用 long 型避免溢出。
[sol1-Java]
1 2 3 4 5 6 7 8 9 10 11
classSolution { publicbooleanjudgeSquareSum(int c) { for (longa=0; a * a <= c; a++) { doubleb= Math.sqrt(c - a * a); if (b == (int) b) { returntrue; } } returnfalse; } }
[sol1-JavaScript]
1 2 3 4 5 6 7 8 9
var judgeSquareSum = function(c) { for (let a = 0; a * a <= c; a++) { const b = Math.sqrt(c - a * a); if (b === parseInt(b)) { returntrue; } } returnfalse; };
[sol1-Golang]
1 2 3 4 5 6 7 8 9
funcjudgeSquareSum(c int)bool { for a := 0; a*a <= c; a++ { rt := math.Sqrt(float64(c - a*a)) if rt == math.Floor(rt) { returntrue } } returnfalse }
[sol1-C++]
1 2 3 4 5 6 7 8 9 10 11 12
classSolution { public: booljudgeSquareSum(int c){ for (long a = 0; a * a <= c; a++) { double b = sqrt(c - a * a); if (b == (int)b) { returntrue; } } returnfalse; } };
[sol1-C]
1 2 3 4 5 6 7 8 9
booljudgeSquareSum(int c) { for (long a = 0; a * a <= c; a++) { double b = sqrt(c - a * a); if (b == (int)b) { returntrue; } } returnfalse; }
复杂度分析
时间复杂度:O(\sqrt{c})。枚举 a 的时间复杂度为 O(\sqrt{c}),对于每个 a 的值,可在 O(1) 的时间内寻找 b。
空间复杂度:O(1)。
方法二:双指针
不失一般性,可以假设 a \le b。初始时 a = 0,b = \sqrt{c,进行如下操作:
如果 a^2 + b^2 = c,我们找到了题目要求的一个解,返回 true;
如果 a^2 + b^2 < c,此时需要将 a 的值加 1,继续查找;
如果 a^2 + b^2 > c,此时需要将 b 的值减 1,继续查找。
当 a = b 时,结束查找,此时如果仍然没有找到整数 a 和 b 满足 a^2 + b^2 = c,则说明不存在题目要求的解,返回 false。
[sol2-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { publicbooleanjudgeSquareSum(int c) { longleft=0; longright= (long) Math.sqrt(c); while (left <= right) { longsum= left * left + right * right; if (sum == c) { returntrue; } elseif (sum > c) { right--; } else { left++; } } returnfalse; } }
[sol2-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var judgeSquareSum = function(c) { let left = 0; let right = Math.floor(Math.sqrt(c)); while (left <= right) { const sum = left * left + right * right; if (sum === c) { returntrue; } elseif (sum > c) { right--; } else { left++; } } returnfalse; };
[sol2-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
funcjudgeSquareSum(c int)bool { left, right := 0, int(math.Sqrt(float64(c))) for left <= right { sum := left*left + right*right if sum == c { returntrue } elseif sum > c { right-- } else { left++ } } returnfalse }
[sol2-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution { public: booljudgeSquareSum(int c){ long left = 0; long right = (int)sqrt(c); while (left <= right) { long sum = left * left + right * right; if (sum == c) { returntrue; } elseif (sum > c) { right--; } else { left++; } } returnfalse; } };
[sol2-C]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
booljudgeSquareSum(int c) { long left = 0; long right = (int)sqrt(c); while (left <= right) { long sum = left * left + right * right; if (sum == c) { returntrue; } elseif (sum > c) { right--; } else { left++; } } returnfalse; }
复杂度分析
时间复杂度:O(\sqrt{c})。最坏情况下 a 和 b 一共枚举了 0 到 \sqrt{c 里的所有整数。
空间复杂度:O(1)。
方法三:数学
费马平方和定理告诉我们:
一个非负整数 c 如果能够表示为两个整数的平方和,当且仅当 c 的所有形如 4k + 3 的质因子的幂均为偶数。