📌  相关文章
📜  范围内的数字计数,其中数字包含的位数不超过K个非零数字(1)

📅  最后修改于: 2023-12-03 15:41:26.268000             🧑  作者: Mango

范围内的数字计数

本篇文章将介绍如何计算一个范围内的数字数量,其中数字包含的位数不超过K个非零数字。

算法思路

首先,我们需要对这个问题进行分类讨论。

假设范围是[1, N],K为数字包含的最大非零位数。

  1. 当K=1时,我们只需要计算[1, 9]范围内的数字数量即可;
  2. 当K=2时,我们需要计算[1, 9]和[11, 99]范围内的数字数量;
  3. 当K=3时,我们需要计算[1, 9]、[11, 99]和[111, 999]范围内的数字数量;
  4. 以此类推,直到K=N的时候,我们需要计算[1, 9]、[11, 99]、[111, 999]、...、[1...N]范围内的数字数量。

对于每个范围,我们需要确定其中的数字有多少位是非零的。假设一个数字的值为x,则其非零位数根据位数的计算方式为:log10(x)。

接下来,我们需要计算一个范围内所有数字的非零位数之和。这个问题可以通过使用数位dp来解决,具体来说,我们可以使用动态规划的思路来解决这个问题。

代码实现

以下是伪代码实现:

// 计算1~x中有多少个数字的非零位数之和
int dp(int x) {
    if (x == 0) {
        return 0;
    }
    vector<int> num;
    while (x > 0) {
        num.push_back(x % 10);
        x /= 10;
    }
    int len = num.size();
    int res = 0;
    int nonzero = 0;
    int k = len - 1;
    for (int i = len - 1; i >= 0; i--) {
        int cur = num[i];
        int cnt = 0;
        for (int j = 0; j < cur; j++) {
            if (j != 0 || i != len - 1) {
                cnt++;
            }
            if (j == nonzero) {
                cnt++;
            }
        }
        res += cnt * k * (k + 1) / 2 + cnt * dp(pow(10, k) - 1) + cnt * (nonzero == cur ? dp(x % (int)pow(10, k)) : 0);
        if (nonzero == cur) {
            break;
        }
        if (cur != 0) {
            res += pow(10, k);
            nonzero = cur;
        }
        k--;
    }
    return res;
}

// 主函数
int countDigit(int n, int k) {
    return dp(n) - dp(pow(10, k) - 1);
}
参考资料
  • 《算法竞赛进阶指南》