贪心·完美整数 | 豆包MarsCode AI刷题

112 阅读5分钟

问题描述

一个整数如果由相同的数字构成,则称为完美整数。例如:

  • 111333 是完美整数。
  • 1219101 是不完美整数。

现在,你需要计算给定区间 [x, y] 中有多少个整数是完美整数。


测试样例

样例1:

输入:x = 1 ,y = 10
输出:9

样例2:

输入:x = 2 ,y = 22
输出:10


思路

分析题目,将大问题分成多个小问题,分成是单位数或者多位数的情况;

  1. 单位数:使用i/10 == 0来判断,并且计算个数。
  2. 多位数
    • ①计算整数的位数
    • ②拆分每一位数字
    • ③判断每个数是否相同

image.png


其中,多位数的情况见以下分析以及代码,例子为判断222是否为完美整数

多位数的情况分析

  • ①计算整数的位数:

创建一个数组用于存储整数中的每个数字,数组长度 为 整数i的位数dCount,其关系为 10^(dC - 1) = i。(如222是3位数,其对应的最大值100是10^2,即dC整数的位数为3,i=222,100 = 10^2 = 10^(3-1) = 10^(dC-1))

----> 整数的位数:dC = Math.log10(i) + 1

int dCount = (int) Math.log10(i) + 1;
  • ②拆分每一位数字

已知整数位数,用for循环遍历,每位数通过num/Math.pow(10,dC-j-1)计算,即用num/10^(dC-j-1)。(如222,要取出第一个数2,会使用222/100,这是num=222,100=10^2=10^(3-1-j),j=0)

通过j的变化和每次取出前一个数将其减掉,num = num - digits[j] * dr,即num = num- num/dr * dr。(如222,num = 222,dC = 3,dr = 10^2 = 100,则num = num - (int)(num/dr) *dr = 222 - * (int)(222/100) * 100 = 222 - 2 * 100 = 222-200 = 22,则22为下一个num

int[] digits = new int[dCount];
int num = i;
// 拆分每一位数字,为 digits 数组
for(int j = 0;j < dCount;j++){
    int dr = (int) Math.pow(10,dCount - j - 1);
    // System.out.println("dr = " + dr);
    digits[j] = num / dr;
    num -= digits[j] * dr;
}
  • ③判断每个数是否相同

当数组中前一个数和后一个数不相同时,通过break跳出外层循环,该数不符合完美整数的定义;当数组中前一个数和后一个数相同时,依次遍历,直到数组的末尾,返回1则表示遍历成功,该数符合条件,令计数sum加一。

// 判断每个数字是否相同
    for(int j = 0;j < digits.length-1;j++){
        // 假设头一个数和下一个数不相等,则直接退出外层循环
        if(digits[j] != digits[j+1]){
            break;
        }
        if(j == digits.length-2){
            System.out.println("成功");
            return 1;
        }
    }
    // 输出数组进行检查
    System.out.println(Arrays.toString(digits));
    return 0;

多位数的情况的完整测试代码:

import java.util.Arrays;

public class Main {
    public static int solution1(int i){
        int dCount = (int) Math.log10(i) + 1;
        int[] digits = new int[dCount];
        int num = i;
        // 拆分每一位数字,为 digits 数组
        for(int j = 0;j < dCount;j++){
            int dr = (int) Math.pow(10,dCount - j - 1);
            // System.out.println("dr = " + dr);
            digits[j] = num / dr;
            num -= digits[j] * dr;
        }
        // 判断每个数字是否相同
        for(int j = 0;j < digits.length-1;j++){
            // 假设头一个数和下一个数不相等,则直接退出外层循环
            if(digits[j] != digits[j+1]){
                break;
            }
            if(j == digits.length-2){
                System.out.println("成功");
                return 1;
            }
        }
        System.out.println(Arrays.toString(digits));
        return 0;
    }
    public static void main(String[] args) {
        // System.out.println(solution1(222) );
    }
}

完整代码

import java.util.Arrays;

public class Main {
    public static int solution(int x, int y) {
        // 如果是单个数,出现多少个就有多少个完美整数;如果不是单个数,那么当每个数是一样的 则是完美整数
        int sum = 0;
        for(int i = x;i <= y;i++){
            // 单个数的情况
            if(i/10 == 0){
                sum++;
            }
            // 多个数的情况
            else{
                // 计算整数的位数。 dCount 表示有几位数字。如222/100,10^2,有3位。即 10^(dC - 1) = i ====》dC 为 该数字有几位
                int dCount = (int) Math.log10(i) + 1;
                int[] digits = new int[dCount];
                int num = i;
                // 拆分每一位数字
                for(int j = 0;j < dCount;j++){
                    int dr = (int) Math.pow(10,dCount - j - 1);
                    digits[j] = num / dr;
                    num -=digits[j] * dr;
                }

                // 判断每个数字是否相同
                for(int j = 0;j < digits.length-1;j++){
                    // 假设头一个数和下一个数不相等,则直接退出外层循环
                    if(digits[j] != digits[j+1]){
                        break;
                    }
                    if(j == digits.length-2){
                        sum++;
                    }
                }

            }
        }
        return sum;
    }
    public static void main(String[] args) {
        
        // System.out.println(solution(1, 10) == 9);
        System.out.println(solution(2, 22) == 10);
        // System.out.println(solution(220, 222) );
    }
}


知识点整理

  • log函数:int x = (int) Math.log10(i) -------log x = i
  • 指数函数:int x = (int) Math.pow(10,i)------10^i = x
  • 拆分整数中的每一位数:

int[] digits = new int[dCount];
int num = i;
// 拆分每一位数字,为 digits 数组
for(int j = 0;j < dCount;j++){
    int dr = (int) Math.pow(10,dCount - j - 1);
    // System.out.println("dr = " + dr);
    digits[j] = num / dr;
    num -= digits[j] * dr;
}

num/10^(dC-j-1)。(如222,要取出第一个数2,会使用222/100,这是num=222,100=10^2=10^(3-1-j),j=0)

通过j的变化和每次取出前一个数将其减掉,num = num - digits[j] * dr,即num = num- num/dr * dr。(如222,num = 222,dC = 3,dr = 10^2 = 100,则num = num - (int)(num/dr) *dr = 222 - * (int)(222/100) * 100 = 222 - 2 * 100 = 222-200 = 22,则22为下一个num

  • 输出数组进行检查:

    System.out.println(Arrays.toString(digits));,直接输出 则结果是哈希码,并且数组中各元素的值,使用Arrays.toString(x)输出数组,并要求引入包名import java.util.Arrays;
  • 分类讨论,将大问题转换成多个小问题,再将小问题挨个解决。

感受

越做越娴熟,赞。由于Java方面比较不熟悉,将问题拆成挨个小问题后,在针对性的进行解决。参考每个小问题对应的解决方法,学习整理,并查看是否能解决当前我所面对问题,该如何调试能够解决问题,如果出现问题了,又该如何调试查找到问题所在,挨个尝试了,并找到最终的解决方案了。♥

参考:

image.png

image.png