多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

LeetCode 633 平方数之和

LeetCode 633 平方数之和 LeetCode 633 题目题号633 题目名称平方数之和 Sum of Square Numbers难度中等题目原文中文描述给定一个非负整数c判断是否存在两个整数 a 和 b满足a2b2ca^2 b^2 ca2b2ca,b 可以是0也可以相等。示例示例1输入c 5输出true解释12221451^2 2^2 1451222145示例2输入c 3输出false解释找不到两个整数平方相加等于3提示约束0≤c≤231−10 \le c \le 2^{31}-10≤c≤231−1费曼学习法讲解破解思路假装讲给小白第一步读懂问题缩小搜索范围我们要找两个数字平方加起来等于c。有一个关键点a 和 b 都不能大于c\sqrt{c}c​举例子c55\sqrt{5}5​≈2.236。如果a33293^29329已经比5大再加任何非负数平方只会更大不可能等于5。 所以 a、b 的范围一定在0 ~ int(sqrt(c))之间。误区很多新手会写双重循环a从0遍历cb从0遍历c时间爆炸。我们只需要遍历到根号c。三种主流解法思路拆解解法1枚举a 判断剩余值是不是完全平方最简单好理解a从0遍历到c\sqrt{c}c​计算剩余值b2c−a2b^2 c - a^2b2c−a2判断这个剩余值是不是某个整数b的平方。如果是 → 返回True循环走完都没有 → 返回False。解法2双指针面试最优推荐O(c\sqrt{c}c​)空间O(1)左指针 left0右指针 right int(sqrt©)计算sum left² right²sum c ✅ 找到return Truesum c总和太小需要变大 → left 1sum c总和太大需要变小 → right -1循环条件left right指针交叉还没找到返回False原理平方序列是单调递增双指针向内收缩一次遍历不用嵌套。解法3费马平方和定理纯数学解法最优雅但面试写起来麻烦费马平方和定理一个自然数 c 能写成两个整数平方之和当且仅当c 所有形如4k34k34k3的质因子它的幂次全部是偶数。举例c9质因子33403幂次是2偶数023290^23^2902329→ truec7质因子7413幂次1奇数无法写成两平方之和。优点纯数论速度快缺点需要写质因数分解写代码长容易写错算法面试一般优先双指针。复杂度汇总枚举完全平方判断O(c)O(\sqrt{c})O(c​)O(1)双指针O(c)O(\sqrt{c})O(c​)O(1)费马定理O(c)O(\sqrt{c})O(c​)O(1)Python代码每行大量注释方案1双指针面试首选# 导入数学模块用于求平方根importmathclassSolution:defjudgeSquareSum(self,c:int)-bool: LeetCode 633平方数之和 :param c: 输入非负整数 :return: bool是否存在a,b满足a²b²c # 左指针从最小整数0开始left0# 右指针取c的平方根向下取整。a,b最大不会超过这个值rightint(math.sqrt(c))# 循环条件left不能超过right防止重复查找whileleftright:# 计算当前两个指针数字的平方和square_sumleft*leftright*right# 情况1平方和正好等于c找到答案直接返回Trueifsquare_sumc:returnTrue# 情况2平方和 c总和太小需要增大总和左指针右移elifsquare_sumc:left1# 情况3平方和 c总和太大需要减小总和右指针左移else:right-1# 循环结束所有组合都试过没有找到返回FalsereturnFalse# 测试代码if__name____main__:solSolution()print(sol.judgeSquareSum(5))# True 1²2²5print(sol.judgeSquareSum(3))# Falseprint(sol.judgeSquareSum(4))# True 0²2²4print(sol.judgeSquareSum(25))# True 3²4²25方案2枚举a 判断剩余数是否完全平方importmathclassSolution:defjudgeSquareSum(self,c:int)-bool: 思路枚举a计算b² c-a²检查b²是不是完全平方数 # a的上限根号ca不能超过这个值max_aint(math.sqrt(c))# a从0循环到max_a包含两端forainrange(0,max_a1):# 算出b的平方b_squarec-a*a# 开平方得到bbint(math.sqrt(b_square))# 判断b的平方是否等于b_square确认是完全平方ifb*bb_square:returnTrue# 遍历全部a没有找到返回FalsereturnFalse# 测试if__name____main__:sSolution()print(s.judgeSquareSum(5))print(s.judgeSquareSum(10))# True, 1910方案3费马平方和定理数学版拓展学习classSolution:defjudgeSquareSum(self,c:int)-bool: 费马平方和定理 c能表示为两平方和所有形如4k3的质因子幂必须是偶数 # 从最小质因子2开始试除base2# base最多遍历到根号cwhilebase*basec:# 如果base不是c的因子直接看下一个ifc%base!0:base1continue# 记录当前质因子base的幂次power0# 不断整除base统计幂whilec%base0:cc//base power1# 判断质因子满足4k3并且幂次是奇数 → 直接falseifbase%43andpower%2!0:returnFalsebase1# 退出循环剩下的c本身是质数# 如果剩下的质数是4k3并且幂次1(奇数)返回Falsereturnc%4!3应用场景举例密码学 / 数论加密RSA、椭圆曲线密码中大量用到平方和、数的平方分解费马平方和定理是数论密码的基础工具用来判断整数的平方分解性质。几何平面坐标平面上两点距离公式d2(x1−x2)2(y1−y2)2d^2(x_1-x_2)^2(y_1-y_2)^2d2(x1​−x2​)2(y1​−y2​)2给定距离平方d²判断是否存在整数坐标点。例如距离平方等于5存在整数坐标差(1,2)两点之间距离√5。游戏、GIS地理坐标网格寻路会用到这类判断。图形渲染、像素网格在像素网格里判断是否存在整数坐标满足距离条件用于光栅化、碰撞检测。数学竞赛、OJ算法题库这道题是经典的双指针模板题同类问题两数之和三数之和。学会双指针向内收缩的思想可以迁移到大量数组搜索类题目。数字图像处理部分图像特征提取会对像素距离做整数平方校验。面试常见坑点总结c0020200^20^2002020→ True代码要覆盖。a或b可以等于0不要从a1开始遍历。语言溢出问题C/Java中left*left大数会溢出Python大整数不会溢出所以不用额外处理。平方根浮点误差不能直接sqrt(b_square) int推荐用b*b b_square校验。
返回列表