计数问题(思维题目)
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)