完美整数 | 豆包MarsCode AI刷题

83 阅读3分钟

题解:判断区间中的完美整数数量

问题描述

一个整数是完美整数,当且仅当它的所有位数都相同。例如:1、11、333 是完美整数,而 12、19、101 则不是。
我们需要计算区间 [x, y] 中所有完美整数的数量。

AC代码

public class Main {
    public static int solution(int x, int y) {
        // Edit your code here
        int count = 0;
        for(int i = x; i <= y; i++){
            if (check(i)) {
                count++;
            }
        }
        return count;
    }

    private static boolean check(int x) {
        String xs = Integer.toString(x);
        char[] xc = xs.toCharArray();
        char tmp = xc[0];
        for (char c : xc) {
            if (c != tmp) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        // Add your test cases here
        
        System.out.println(solution(1, 10) == 9);
        System.out.println(solution(2, 22) == 10);
    }
}

代码分析

  1. 核心函数 solution(int x, int y)

    • 遍历区间 [x, y] 中的每个整数 i
    • 对每个 i 调用辅助函数 check(int x) 检查是否为完美整数。
    • 累计满足条件的整数个数并返回。
  2. 辅助函数 check(int x)

    • 将整数 x 转为字符串,随后转为字符数组。
    • 比较所有字符是否与第一个字符相同,若不相同返回 false,否则返回 true
  3. 测试用例

    • solution(1, 10),期望输出为 9,因为除 10 以外,其余均为完美整数。
    • solution(2, 22),期望输出为 10,因为 [2, 22] 内所有个位和十位数字均相同的整数是:2、3、...、9、11、22。

时间复杂度

  1. 区间长度为 n = y - x + 1
    • 对于每个数字调用 check(),其复杂度为 O(d),其中 d 为数字位数。
    • 因此总复杂度为 O(n * d)
  2. 若区间较大或数字位数较多,该实现效率较低。

改进方案

现有实现通过字符串和数组的转换来判断每个数的位是否相同,存在一定的开销。可以优化为 数学运算直接生成完美整数 的方式,减少遍历和检查。

方案一:使用数学运算优化 check()

无需转换为字符串,可直接通过数值运算判断每一位是否相同:

private static boolean check(int x) {
    int lastDigit = x % 10; // 获取最后一位
    while (x > 0) {
        if (x % 10 != lastDigit) {
            return false; // 存在不同的数字
        }
        x /= 10; // 去掉最后一位
    }
    return true;
}

这种方式避免了字符串操作,直接基于整数运算实现,效率更高。

方案二:直接生成完美整数

完美整数具有规律性(如 1, 2, ..., 9, 11, ..., 99, 111...)。我们可以跳过所有非完美整数的判断,直接生成完美整数并检查是否在 [x, y] 范围内:

public static int solution(int x, int y) {
    int count = 0;
    for (int digit = 1; digit <= 9; digit++) {
        int num = digit; // 初始为单个数字
        while (num <= y) {
            if (num >= x) {
                count++;
            }
            num = num * 10 + digit; // 构造下一个完美整数
        }
    }
    return count;
}
  1. 外层循环枚举数字 1~9 作为重复数字。
  2. 内层循环构造完美整数(如 1, 11, 111...)并判断是否在 [x, y] 范围内。
  3. 跳过不必要的检查操作,复杂度降低到与区间内完美整数的数量相关。

改进的时间复杂度

  1. 构造完美整数最多需要生成每个位数的 9 个数字:
    • 复杂度约为 O(log(y))
  2. 相较于暴力枚举 O(n * d),显著减少了非完美整数的计算。

总结

  1. 当前代码优点:逻辑清晰,适合小范围测试。
  2. 缺点:时间复杂度高,当区间较大或数字位数多时效率较低。
  3. 优化方向
    • 使用数学运算代替字符串操作(方案一)。
    • 利用完美整数规律直接生成结果(方案二)。