题目:
给定一个非负整数 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 <= 2的31次幂减1
暴力破解
思路:
首先,我们分析下题目,如果想要找到两个数的平方和等于给定的c的值;我们可以想到以下条件:
如果符合条件的a,b存在,那么a和b这两个数一定在0和sqrt©之间
最简单的也是最容易想到的思路:暴力破解–
对于两层范围在[0,sqrt©]的for循环,如果找到ii+jj的值与给定的c相等,那么返回true,否则返回false。
但是,对于给定的数字规模2的31次幂-1这样大的数字,这样没有技术含量的算法是一定会超时的,代码和结果如下给出:
class Solution {
public boolean judgeSquareSum(int c) {
int tar = (int)Math.sqrt((double)c);
for(int i=0;i<=tar;i++) {
for(int j = 0;j<=tar;j++) {
if(i*i+j*j == c) {
return true;
}
}
}
return false;
}
}
暴力破解凉了,现在我们需要再想一个更好的方法:
由于c是由两个动态的数字平方和组成的,我们可以尝试双指针方法
双指针
由于双指针只需要一次遍历,一边来说是不会超时的。
先贴出代码,下面详细讲一下双指针的问题:
class Solution {
public boolean judgeSquareSum(int c) {
int low = 0;
int high = (int)Math.sqrt(c);
while(low <= high){
int sum = low*low+ high*high;
if(sum == c) {
return true;
}
else if(sum > c) {
high--;//下面会讲
}
else {
low++;//下面会讲
}
}
return false;
}
}
结果:
但是,为什么双指针不会把正确答案排除在外呢?我认为这才是我们应该考虑的问题;接下来写出双指针的变化过程
首先,定义两个指针;第一个假定为i,初始指向 i = 0(从最开始考虑)
然后,第二个定为j,初始指向 j = (int)sqrt(c);
二者开始同时移动
判定条件1.如果满足(axa+bxb<c)这样的条件下,显然,在a固定的情况下和无论如何变化b值都不会满足当前的条件,由此,a=0一定不在正确答案中,所以可以直接排除。
判定条件2.反之,if(axa+bxb>c),在b固定的情况下,当前所有能变化的a值,都不会满足条件 == c,因此,当前的b也一定不在正确答案中。
综上所述,因为在算法运行过程中不会排除掉正确答案,我们可以采用双指针法进行求解。
上面这段话虽然说明白了,但是大家可能没看明白;
我认为还是用图来讲更易理解一点~
因此我找了很多题解,认为下面这篇最容易理解:
https://leetcode-cn.com/problems/sum-of-square-numbers/solution/shuang-zhi-zhen-de-ben-zhi-er-wei-ju-zhe-ebn3/
下面讲解这个题解的思想:
把整个双指针搜索的过程可以看作一个在二维矩阵中搜索的过程,如下:
c = 18,初始化得到i = 0,j = 4;其中每个元素代表ixi加上jxj的值,黄色格子代表当前的ixi+jxj的值,绿色格子代表给定c的值
low++的操作相当于让黄色格子向下移一行进行搜索,high–的操作相当于让黄色格子所在列向左移一列进行搜索
在每次查找的过程中,都存在以下性质:
1.初始化时黄色格子(sqrt(c)的值)必定在矩阵的右上角。
2.每次进行low++或者high–的操作如果没取得 ixi+jxj == c的值,那么一定可以排除一行或一列
借用大佬的图方便大家理解↓:
由于搜索的行为会使黄色格子的右侧和上侧所有格子逐渐被排除,因此黄色格子在被搜索的过程中仅存在两种可能性:
1.搜索小于c的情况 :左边的元素都小于黄色格子元素,只能下移,相当于low++。此时排除的是黄色格子以及左边同行的元素,都小于 c ,所以不会错过正确答案。
2.搜索大于c的情况:下面的元素都大于黄色格子元素,只能左移,相当于high–。此时排除的是黄色格子以及下方同列的元素,都大于 c ,所以不会错过正确答案。
综上所述,使用双指针不会错过正确答案~
特殊解法:数学
引入费马平方和定理这一概念,概念告诉我们:
一个非负整数 c 如果能够表示为两个整数的平方和,当且仅当 c 的所有形如 4k + 3 的质因子的幂均为偶数。
因此对 c 进行质因数分解,再判断所有形如 4k + 3 的质因子的幂是否均为偶数即可
这里不详细讲解,有兴趣的同学可以自己去查~