leetcode 633.平方数之和(双指针详解)

本文探讨了一种高效的算法,利用双指针法解决LeetCode上的判断非负整数c是否可以表示为两个整数平方和的问题。通过数学原理和二维矩阵搜索视角,展示了如何避免暴力搜索并确保正确答案不被排除。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:
给定一个非负整数 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 的质因子的幂是否均为偶数即可
这里不详细讲解,有兴趣的同学可以自己去查~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵奕升

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值