题目描述

✅ 507. 完美数

image-20260928224254316

题意分析

判断正整数 num 是否等于所有真因子之和。真因子是能整除 num 且小于它的正整数,所以必须排除 num 自身。对 num>1,因子 1 要计入;1 自己没有真因子,因此不是完美数。

解法:遍历因子成对求和

核心思路

[!blue]

若 i 能整除 num,另一个因子就是 num/i。一对因子的乘积为 num,至少有一个不超过平方根,所以只枚举较小者,就能找到全部因子对,无需一直扫描到 num-1。

先把因子对 (1,num) 单独处理:总和初始化为 1,不加入 num,循环从 2 开始。之后找到的因子对,两项都小于 num,可以计入真因子和;若两项相等,说明它们都是平方根,只能加一次。

枚举条件写成 i <= num/i,对正整数等价于 i*i <= num,同时避免先做平方乘法。每个非平方因子对只会由它的较小成员触发,平方因子又做了去重,因此循环结束时,总和既没有遗漏也没有重复,直接与 num 比较即可。

解题步骤

  • 一的真因子和为零,直接返回假。
  • 总和从一开始,枚举满足 i<=num/i 的小因子。
  • 整除时加入 i 与不同的配对因子。
  • 比较总和与原数。

质数不会找到额外因子,最终总和保持为 1;完全平方数必须包含平方根这一项,因此循环上界要取等号。

代码实现

class Solution {
    public boolean checkPerfectNumber(int num) {
        // 1 的真因子和为 0,而下面 sum 初值为 1,必须提前挡掉。
        if (num <= 1) {
            return false;
        }

        // 初值 1 相当于手工拆开因子对 (1, num):计入 1,排除 num 自身。
        int sum = 1;

        for (int i = 2; i <= num / i; i++) {
            if (num % i == 0) {
                sum += i;
                int other = num / i;

                // num 是完全平方数时 other 与 i 重合,只能算一次。
                if (other != i) {
                    sum += other;
                }
            }
        }

        return sum == num;
    }
}
func checkPerfectNumber(num int) bool {
    // 1 的真因子和为 0,而下面 sum 初值为 1,必须提前挡掉。
    if num <= 1 {
        return false
    }
    // 初值 1 相当于手工拆开因子对 (1, num):计入 1,排除 num 自身。
    sum := 1
    for i := 2; i <= num/i; i++ {
        if num%i == 0 {
            sum += i
            other := num / i
            // num 是完全平方数时 other 与 i 重合,只能算一次。
            if other != i {
                sum += other
            }
        }
    }
    return sum == num
}

复杂度分析

  • 时间复杂度:$O(\sqrt{num})$,每对因子只枚举较小者。
  • 空间复杂度:$O(1)$,只保存计数与配对值。

关键点总结

[!green]

  • 每个因子都有配对值,只需枚举到平方根便能覆盖全部因子。
  • 单独处理 (1,num) 排除自身,判断两因子是否相等消除平方根重复。

易错点总结

[!yellow]

  • 把自身加入总和,却仍与原数比较,混淆了真因子口径。
  • 平方根加两次,会错误扩大因子和。
  • 总和从零开始却仍从二枚举,会漏掉因子一。
  • 扩大枚举到半数却仍按因子对累加,会重复计算已经处理的因子对。

相似题目

题目 难度 关联与区别
1390. 四因数 中等 同样成对枚举因子并累加因子和,原题还限制恰有四个因子,本题比较真因子和与原数。
319. 灯泡开关 中等 同样利用因子配对,完全平方数的平方根只计一次,原题据此判断因子个数奇偶。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/12215213
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!