给定c,寻找满足 a 2 + b 2 = c a^2+b^2=c a2+b2=c的a和b
其中 0 < = c < = 2 31 − 1 0 <= c <= 2^{31} - 1 0<=c<=231−1.
输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
解题整理:
1.暴力枚举
对于给定的非负整数 c,需要判断是否存在整数 a 和 b,使得 a 2 + b 2 = c a^2+b^2=c a2+b2=c。可以枚举 a和 b 所有可能的情况。但是暴力枚举有一些情况是没有必要的。例如:当 c = 20时,当 a = 1 的时候,枚举 b的时候,只需要枚举到 b = 5就可以结束了,这是因为 1 2 + 5 2 = 26 > 20 1^2+5^2=26>20 12+52=26>20当 b > 5 时,一定有 1 2 + b 2 > 20 1^2 + b^2 > 20 12+b2>20。
在枚举 a 的同时,使用 sqrt 函数找出 b。注意:c 的取值范围在 [ 0 , 2 31 − 1 ] [0,2^{31} - 1] [0,231−1],因此在计算的过程中可能会发生 int 型溢出的情况,需要使用long 型避免溢出。
class Solution {
public boolean judgeSquareSum(int c) {
for (long a = 0; a * a <= c; a++) {
double b = Math.sqrt(c - a * a);
if (b == (int) b) {
return true;
}
}
return false;
}
}
2.使用双指针枚举
可以假设 a ≤ b a≤b a≤b。初始时 a = 0, b = c b = \sqrt{c} b=c,进行如下操作:
- 如果 a 2 + b 2 = c a^2 + b^2 = c a2+b2=c,我们找到了要求的一个解,返回 true \text{true} true;
- 如果 a 2 + b 2 < c a^2 + b^2 < c a2+b2<c,则a++;
- 如果
a
2
+
b
2
>
c
a^2 + b^2 > c
a2+b2>c,则b–;
当 a = b 时,结束查找,此时如果仍然没有找到整数 a 和 b 满足 a 2 + b 2 = c a^2 + b^2 = c a2+b2=c,则说明不存在要求的解,返回 false \text{false} false.
双指针为什么有用,可以参考链接
class Solution {
public boolean judgeSquareSum(int c) {
long left = 0;
long right = (long) Math.sqrt(c);
while (left <= right) {
long sum = left * left + right * right;
if (sum == c) {
return true;
} else if (sum > c) {
right--;
} else {
left++;
}
}
return false;
}
}
3.使用双指针枚举
费马平方和定理: 一个非负整数 c c c 如果能够表示为两个整数的平方和,当且仅当 c c c 的所有形如 4 k + 3 4k + 3 4k+3 的质因子的幂均为偶数。
因此我们需要对 c c c 进行质因数分解,再判断所有形如 4 k + 3 4k + 3 4k+3的质因子的幂是否均为偶数即可。
class Solution {
public boolean judgeSquareSum(int c) {
for (int base = 2; base * base <= c; base++) {
// 如果不是因子,枚举下一个
if (c % base != 0) {
continue;
}
// 计算 base 的幂
int exp = 0;
while (c % base == 0) {
c /= base;
exp++;
}
// 根据 Sum of two squares theorem 验证
if (base % 4 == 3 && exp % 2 != 0) {
return false;
}
}
return c % 4 != 3;
}
}