数字统计

51 阅读1分钟

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

解题思路

对于大范围  内的数字统计,需要使用数位DP的方法:

  1. 将问题转化为求 ,表示  到  中每个数字出现的次数

    • 则区间  的答案为 
  2. 对于计算 

    • 考虑每一位的贡献

    • 例如对于数字 

      • 个位:每  个数, 各出现  次
      • 十位:每  个数,每个数字在十位上出现  次
      • 百位:每  个数,每个数字在百位上出现  次
      • 千位: 出现  次, 出现  次, 出现  次
  3. 核心思路:

    • 对每一位,计算该位上的每个数字出现次数
    • 需要考虑当前位是否受限
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
    // Write your code here
    let params = [];
    while ((line = await readline())) {
        let tokens = line.split(" ");
        // let a = parseInt(tokens[0]);
        // let b = parseInt(tokens[1]);
        // console.log(a + b);
        params.push(tokens);
    }
    // console.log(params)
    let start = parseInt(params[0][0]);
    let end = parseInt(params[0][1]);

    function count(n) {
        let pos = 1;
        let cnt = new Array(10).fill(0);
        while (n >= pos) {
            let high = Math.floor(n / (pos * 10));
            let curr = Math.floor(n / pos) % 10;
            let low = n % pos;
            // console.log(high, curr, low);
            for (let digit = 0; digit < 10; digit++) {
                cnt[digit] += high * pos;
                if (digit < curr) {
                    cnt[digit] += pos;
                } else if (digit === curr) {
                    cnt[digit] += low + 1;
                }
                if (digit === 0) {
                    cnt[0] -= pos;
                }
            }
            pos *= 10;
        }
        return cnt;
    }
    let arr1 = count(start - 1);
    let arr2 = count(end);
    let str = "";
    for (let i = 0; i < arr1.length; i++) {
        str += Math.abs(arr1[i] - arr2[i]) + " ";
    }
    console.log(str);
})();