题目
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。
示例 1:
输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
示例 2:
输入:c = 3
输出:false
示例 3:
输入:c = 4
输出:true
示例 4:
输入:c = 2
输出:true
示例 5:
输入:c = 1
输出:true
提示:
0 <= c <= 231 - 1
题解
方法一:sqrt 函数
class Solution {
public boolean judgeSquareSum(int c) {
// long型避免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;
}
}
复杂度分析
-
时间复杂度:O(根号c)
- 枚举 a的时间复杂度为O(根号c)
对于每个 a的值,可在 O(1)的时间内寻找 b。
- 枚举 a的时间复杂度为O(根号c)
-
空间复杂度:O(1)。
方法二:双指针
假设 a≤b。初始时 a=0,b =根号c
,进行如下操作:
- 如果 a2 + b2 = c,找到一个解,返回 true;
- 如果 a2 + b2 <c,将 a的值加 111,继续查找;
- 如果 a2 + b2 >c,将 b 的值减 111,继续查找。
当 a=b时,结束查找
此时如果仍然没有找到整数 a 和 b 满足 a2 + b2 = c,
则说明不存在题目要求的解,返回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;
// int a=0;long b=(int)Math.sqrt(c);
// while(a<=b){
// if(a*a+b*b==c){
// return true;
// }else if(a*a+b*b<c){
// a++;
// }else{
// b--;
// }
// }
// return false;
}
}
复杂度分析
- 时间复杂度:O(根号c)
- 最坏情况下 a 和 b一共枚举了 0 到根号c里的所有整数。
- 空间复杂度:O(1)。
方法三:费马平方和定理
一个非负整数 c如果能够表示为两个整数的平方和,当且仅当 c 的所有形如 4k+3 的质因子的幂均为偶数。
证明:https://wstein.org/edu/124/lectures/lecture21/lecture21/node2.html
- 对c进行质因数分解,
- 判断所有的关于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;
}
}
// 例如 11 这样的用例,由于上面的 for 循环里 base * base <= c ,base == 11 的时候不会进入循环体
// 因此在退出循环以后需要再做一次判断
return c % 4 != 3;
}
}
复杂度分析
-
时间复杂度:O(根号c)。
-
空间复杂度:O(1)。
参考链接:https://leetcode-cn.com/problems/sum-of-square-numbers/solution/shuang-zhi-zhen-de-ben-zhi-er-wei-ju-zhe-ebn3/