Leetcode(633)——平方数之和

Leetcode(633)——平方数之和

题目

给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a 2 + b 2 = c a^2 + b^2 = c a2+b2=c

示例 1:

输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5

示例 2:

输入:c = 3
输出:false

提示:

  • 0 0 0 <= c <= 2 31 − 1 2^{31 - 1} 2311

题解

​​  对于给定的非负整数 c c c,需要判断是否存在整数 a a a b b b,使得 a 2 + b 2 = c a^2 + b^2 = c a2+b2=c。可以枚举 a a a b b b 所有可能的情况,时间复杂度为 O ( c 2 ) O(c^2) O(c2)。但是暴力枚举有一些情况是没有必要的。例如:当 c = 20 c = 20 c=20 时,当 a = 1 a = 1 a=1 的时候,枚举 b b b 的时候,只需要枚举到 b = 5 b = 5 b=5 就可以结束了,这是因为 1 2 + 5 2 = 25 > 20 1^2 + 5^2 = 25 > 20 12+52=25>20。当 b > 5 b > 5 b>5 时,一定有 1 2 + b 2 > 20 1^2 + b^2 > 20 12+b2>20

​​  注意到这一点,可以使用 sqrt \texttt{sqrt} sqrt 函数或者双指针降低时间复杂度

方法一:使用标准库函数 sqrt \texttt{sqrt} sqrt

思路

​​  在枚举 a a a 的同时,使用 sqrt \texttt{sqrt} sqrt 函数找出 b b b。注意:本题 c c c 的取值范围在 [ 0 , 2 31 − 1 ] [0,2^{31} - 1] [0,2311],因此在计算的过程中可能会发生 int \texttt{int} int 型溢出的情况,需要使用 long \texttt{long} long 型避免溢出。

代码实现

Leetcode 官方题解:

class Solution {
public:
    bool judgeSquareSum(int c) {
        for (long a = 0; a * a <= c; a++) {
            double b = sqrt(c - a * a);
            if (b == (int)b) {
                return true;
            }
        }
        return false;
    }
};
复杂度分析

时间复杂度 O ( c ) O(\sqrt{c}) O(c )。枚举 a a a 的时间复杂度为 O ( c ) O(\sqrt{c}) O(c ),对于每个 a a a 的值,可在 O ( 1 ) O(1) O(1) 的时间内寻找 b b b
空间复杂度 O ( 1 ) O(1) O(1)

方法二:反向双指针

思路

​​  不失一般性,可以假设 i ≤ m a x i \le max imax。初始时 i = 0 i = 0 i=0 m a x = c max = \sqrt{c} max=c ,进行如下操作:

  • 如果 m a x 2 + i 2 = c max^2 + i^2 = c max2+i2=c,我们找到了题目要求的一个解,返回 true \text{true} true
  • 如果 m a x 2 + i 2 < c max^2 + i^2 < c max2+i2<c,此时需要将 i i i 的值加 1 1 1,继续查找;
  • 如果 m a x 2 + i 2 > c max^2 + i^2 > c max2+i2>c,此时需要将 m a x max max 的值减 1 1 1,继续查找。
  • m a x = i max = i max=i 时,结束查找,此时如果仍然没有找到整数 m a x max max i i i 满足 m a x 2 + i 2 = c max^2 + i^2 = c max2+i2=c,则说明不存在题目要求的解,返回 false \text{false} false

​​  至于反向双指针遍历已排序好的序列的正确性(即如何确保不会漏掉其中的正确答案): 可以参考这里
​​  所以用反向双指针要考虑两个问题:每次移动指针排除掉了哪些情况?这些情况中是否可能包含正确答案?

代码实现

我的:

class Solution {
public:
    bool judgeSquareSum(int c) {
        // 找出平方根小于或等于 c 的最大整数 max
        int max = sqrt(c), i = 0;
        while(i <= max){
            // 不用 max*max + i*i 和 c 比较,因为可能会产生类型溢出
            if(c - max*max == i*i) return true;
            c - max*max < i*i? max--: i++;
        }
        return false;
    }
};
复杂度分析

时间复杂度 O ( c ) O(\sqrt{c}) O(c )。最坏情况下 m a x max max i i i 一共枚举了 0 0 0 c \sqrt{c} c 里的所有整数。
空间复杂度 O ( 1 ) O(1) O(1)

方法三:数学

思路

​​  费马平方和定理告诉我们:

一个非负整数 c c c 如果能够表示为两个整数的平方和,当且仅当 c c c 的所有形如 4 k + 3 4k + 3 4k+3 的质因子的幂均为偶数。

证明请见 这里

​​  因此我们需要对 c c c 进行质因数分解,再判断所有形如 4 k + 3 4k + 3 4k+3 的质因子的幂是否均为偶数即可。

代码实现

Leetcode 官方题解:

class Solution {
public:
    bool 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(\sqrt{c}) O(c )
空间复杂度 O ( 1 ) O(1) O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值