中级 · 计数数组
数字出现次数
统计一个数里每个数字出现的次数,按数字升序输出。你的第一个计数数组 —— 直方图和投票统计背后的同一套模式。
一句话答案用一个 10 格的数组统计每个数字出现次数,然后只把出现过的数字按 digit:count 升序打印 —— 用固定桶数组代替排序。
题目
输入: 一个非负整数(0 <= n <= 1000000000)。
输出: 每个出现过的数字一行:数字:次数,按升序。
样例:
| 输入 | 输出 |
|---|---|
122333 | 1:12:23:3 |
你的解答
「运行我的输入」用的自定义输入
判题在浏览器本地运行。死循环会在 3 秒后被自动中断 —— 但还是确保每个循环都有出口。代码随打随存。
卡住了?提示
提示 1 — 用数组当计数器
int count[10] = {0};,每次切下一位就 count[n % 10]++;。
提示 2 — 只打印出现过的
遍历 0–9,只在 count[d] > 0 时输出 —— 输出零次数会被判错。
题解(先自己试试!)
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int count[10] = {0};
while (n > 0) {
count[n % 10]++;
n /= 10;
}
for (int d = 0; d <= 9; d++) {
if (count[d] > 0) cout << d << ":" << count[d] << endl;
}
return 0;
}
这就是计数排序和直方图的模式:用值当下标,用自增来计数。和两桶版本对照看。
深度解析
为什么这样做对
用值当下标的计数数组,是最简单的哈希表:不用算哈希、不会冲突、天生 O(1) 查找。
代价
O(n + 10) 时间、O(10) 空间。那个常数 10 就是它比排序快一个量级的原因。
常见错法
- 拿 char 当下标拿到的是 ASCII 码('9' 是 57),不是 9。要减 '0'。
- 把十个桶全打印出来,而不是只打印出现过的,会被精确比对判错。
下一步
同样的数组,换个聚合方式:矩阵求和。
记住这两句
- 值当下标 = 不用哈希的哈希表。
- '9' - '0' == 9,这个偏移量就是全部技巧。
🐞 这段是错的 —— 点开,亲手让它挂一次
把十个桶全打印了,而不是只打印出现过的
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int count[10] = {0};
while (n > 0) {
count[n % 10]++;
n /= 10;
}
for (int d = 0; d <= 9; d++) {
cout << d << ":" << count[d] << endl;
}
return 0;
}