《不大于n的好数计数问题》| 豆包MarsCode AI刷题

66 阅读2分钟

今天我们将在豆包MarsCode AI刷题平台上,完成《不大于n的好数计数问题》算法问题

《不大于n的好数计数问题》 内容如下:

image.png

解析:

  • 使用 fn[i] 代表第i位不为0时满足好数的个数, 即k????的好数个数

  • 那么, fn[i] = fn[i-1]*8 + f[i-2]*9

    • 第i位数固定一个不为0的数值k时, 后一位选择不为0且不等于k,有fn[i-1]*8个, 后一位选择0时,有 f[i-2]*9 个
  • 默认 f[0]=1, f[1]=9

  • 得到每个位数下的可选个数后, 从最高位遍历, 对于每一位,可选0或者不为0的数(不等于前值), 直到遇到前一个值和当前值相等, 则跳出.

  • 注意: 在最低位时, 如果满足继续迭代, 结果需要加1

具体实现

public static int solution(int n) {
    int mod = 1000000007;
    //归纳总结: 不包含最高i位,  和包含i位需要剔除第二位不为i
    //f[i]为第i位不为0时,能够多少种好数
    // f[i] = f[i-1]*8 + f[i-2]*9  //表示i-1不等于i, 和i-2不为0
    // f[0]=1   f[1] = 9
    long result = 0;
    long[] fn = new long[12]; 
    int[] values = new int[12];
    fn[0] = 1;
    fn[1] = 9;
    int i = 0;
    while (n > 0) {
        if (i > 0) { //遍历结束,result记录不包含最高位时的好数总和
            result = (result + fn[i - 1] * 9) % mod;
        }
        if (i > 1) {
            fn[i] = (fn[i - 1] * 8 + fn[i - 2] * 9) % mod;
        }
        values[i] = n % 10;
        n /= 10;
        i++;
    }
    i--;
    for (int j = i; j >= 0; j--) {
        //1. 不包含i , [1,i-1]
        if (values[j] > 1) {
            int count = values[j] - 1;
            if (j != i && values[j + 1] < values[j] && values[j + 1] > 0) {
                count--; //上一个数在1到i之间
            }
            result = (result + fn[j] * count) % mod;
        }
        if (i != j) {
            //2. 考虑当前为0
            if (values[j + 1] != 0 && values[j] > 0) {
                result = (result + (j > 0 ? fn[j - 1] * 9 : 1)) % mod;
            }
            if (values[j + 1] == values[j]) {
                break;
            }
            if (j == 0) { //主要时考虑到最后一个数还能使用时, 正好应对步骤1未取的value[j]的情况
                result = (result + 1) % mod;
            }
        }
    }
    return (int) result;
}