top1编程
← 返回题目
题解

梦中的统计

1 条题解

  • 0
    @ 2026-8-5 21:17:14

    P4388 梦中的统计(基础)

    解题思路

    童童从 m 数到 n,要统计这一串数里数字 0 到 9 各出现了多少次。比如从 15 数到 25,就要把 15、16、17……25 每个数的每一位都看清楚、数一遍。

    关键是怎么"拆数":一个整数怎么一位一位拿出来?办法是用取余和整除:t % 10 得到个位,t / 10 去掉个位。不断重复,直到 t 变成 0,每一位就都拆完了。比如 25:25 % 10 = 5,25 / 10 = 2;2 % 10 = 2,2 / 10 = 0,拆出了 5 和 2。

    算法:用一个长度为 10 的计数数组 cnt,对 m 到 n 的每个数做拆位,每拆出一个数字 d 就 cnt[d]++。最后依次输出 cnt[0] 到 cnt[9]。

    拿样例验证 m=15、n=25:15 拆出 1 和 5,16 拆出 1 和 6,20 拆出 2 和 0……统计下来 0 出现 1 次、1 出现 6 次、2 出现 7 次……输出 "1 6 7 1 1 2 1 1 1 1",和样例一致。

    边界情况:n 最大是 1000,每个数最多 4 位,计算量很小。注意数字 0 也可能出现在某个数的某一位上(比如 20 的个位是 0),我们统计的是每一位上出现的数字,所以不会漏。m 最小是 1,每个数至少有一位数字。

    参考代码

    // 程序用途:统计从m到n之间所有整数中数字0~9各出现多少次
    #include <iostream>
    using namespace std;
    
    int main() {
        int m, n;
        cin >> m >> n;
        int cnt[10] = {0};                // cnt[d]记录数字d出现的次数
        for (int i = m; i <= n; i++) {    // 对每个数i
            int t = i;
            while (t > 0) {               // 把i的每一位都拆出来
                cnt[t % 10]++;            // 个位数字计数加1
                t = t / 10;               // 去掉个位,继续看下一位
            }
        }
        for (int i = 0; i < 10; i++) {    // 依次输出0~9的次数
            if (i > 0) cout << " ";
            cout << cnt[i];
        }
        cout << endl;
        return 0;
    }
    

    复杂度分析

    从 m 到 n 一共有 n-m+1 个数,每个数最多拆 4 位,所以时间约是 O(n × 4),也就是 O(n);计数数组长度固定为 10,额外空间复杂度是 O(1)。

    • 1