计数问题(思维题目)
C++
计数问题
/*
问题描述:
给定两个整数 a 和 b,求 a 和 b 之间的所有数字中 0∼9 的出现次数。
例如,a=1024,b=1032,则 a 和 b 之间共有 9 个数如下:
1024 1025 1026 1027 1028 1029 1030 1031 1032
其中 0 出现 10 次,1 出现 10 次,2 出现 7 次,3 出现 3 次等等…
0 < a, b < 100000000
解题思路:
本题思路主要在于讨论,并且一步步将大问题分解为小问题。
Q1 --> 求解 [a, b] 区间中 0, 1, 2, ..., 9 数字的出现个数
Q2 --> 求解 [0, x] 区间中 0, 1, 2, ..., 9 数字的出现个数,因为 [0, b] - [0, a - 1] 即为上一步结果
Q3 --> 求解 [0, x] 区间中 数字 t 的出现次数,将 t 取值 0, ..., 9 即为上述结果。
Q4 --> 求解 [0, x] 区间中,数字 t 在第 i 位上出现的次数,取遍所有的位置,即为上一步的结果。
现在,我们将问题分解的差不多了,求解 Q4
假设数字为 abcdef,第一位数字为 a, 第二位数字为 b,第 i 位数字为 d, 最后一位数字(第 n 位数字)为 f
当 d = t:
当前面取值 abc,第 i 位置取 d,这种情况可以从 (0 .. ef),因为出现次数为 ef + 1
当 t = 0:
(1 .. abc) * 10 ^ (n - i) -> abc * 10 ^ (n - i)
当 t != 0
(0 .. abc) * 10 ^ (n - i) -> (abc + 1) * 10 ^ (n - i)
结果为 (ef + 1) + (abc * 10 ^ (n - i) if t == 0 else (abc + 1) * 10 ^ (n - i))
当 d > t:
当 t == 0:
(1 ... abc) * 10 ^ (n - i) -> abc * 10 ^ (n - i)
当 t != 0:
(0 ... abc) * 10 ^ (n - i) -> (abc + 1) * 10 ^ (n - i)
当 d < t:
当 t == 0:
(1 ... abc-1) * 10 ^ (n - i) -> (abc - 1) * 10 ^ (n - i)
当 t != 0:
(0 ... abc-1) * 10 ^ (n - i) -> abc * 10 ^ (n - i)
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
int pow_10[20];
int cal_num(vector<int> &nums, int l, int r) {
int ret = 0;
for (int i = l - 1; i < r && i < nums.size(); i ++ ) {
ret = ret * 10 + nums[i];
}
return ret;
}
int get_single_digital_cnt_per_position(vector<int> &nums, int i, int digit) {
int pre_num = cal_num(nums, 1, i - 1);
int post_num = cal_num(nums, i + 1, nums.size());
int ret_cnt = 0;
if (nums[i - 1] == digit) {
ret_cnt = post_num + 1;
if (digit == 0) {
ret_cnt += (pre_num - 1) * pow_10[nums.size() - i];
} else {
ret_cnt += (pre_num) * pow_10[nums.size() - i];
}
} else if (nums[i - 1] > digit) {
if (digit == 0) {
ret_cnt += (pre_num) * pow_10[nums.size() - i];
} else {
ret_cnt += (pre_num + 1) * pow_10[nums.size() - i];
}
} else {
if (digit == 0) {
ret_cnt += (pre_num - 1) * pow_10[nums.size() - i];
} else {
ret_cnt += (pre_num) * pow_10[nums.size() - i];
}
}
return ret_cnt;
}
int get_single_digital_cnt(int x, int digit) {
vector<int> nums;
int y = x, len = 0;
if (y == 0) {
len = 1;
nums.push_back(0);
} else {
while (y) {
nums.push_back(y % 10);
y /= 10;
len += 1;
}
reverse(nums.begin(), nums.end());
}
int cnt = 0;
for (int i = 1; i <= len; i ++ ) {
cnt += get_single_digital_cnt_per_position(nums, i, digit);
}
return cnt;
}
vector<int> get_all_digital_cnt(int x) {
if (x == 0) {
vector<int> ret = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
return ret;
}
vector<int> ret;
for (int i = 0; i <= 9; i ++ ) {
ret.push_back(get_single_digital_cnt(x, i));
}
return ret;
}
int main()
{
int a, b;
pow_10[0] = 1;
for (int i = 1; i <= 9; i ++ ) {
pow_10[i] = 10 * pow_10[i - 1];
}
while (scanf("%d%d", &a, &b), a != 0 || b != 0) {
// 确保 a <= b
if (a > b) {
swap(a, b);
}
vector<int> res_a = get_all_digital_cnt(a - 1);
vector<int> res_b = get_all_digital_cnt(b);
printf("%d", res_b[0] - res_a[0]);
for (int i = 1; i < res_b.size(); i ++ ) {
printf(" %d", res_b[i] - res_a[i]);
}
printf("\n");
}
return 0;
}