• 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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    复杂度分析

    时间复杂度 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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    复杂度分析

    时间复杂度 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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    复杂度分析

    时间复杂度 O ( c ) O(\sqrt{c}) O(c )
    空间复杂度 O ( 1 ) O(1) O(1)

  • 相关阅读:
    2024年集创赛FPGA紫光同创赛道男女声,童声变声
    Python----函数中的说明文档
    Airtest的多图查找与两图对比
    PTA 哈密尔回路(建图搜索)
    南大通用GBase8s 常用SQL语句(288)
    [安洵杯 2019]easy_serialize_php1
    Matlab:使用 Filtered-x LMS FIR 自适应滤波器实现有源噪声控制
    python之模拟登录与表单交互
    Win10怎么快速删除超大数量文件群
    互联网应用开发实践:需求分析与数据库设计
  • 原文地址:https://blog.csdn.net/KCDCY/article/details/125524301