Count of Integers
Count of Integers
You are given two numeric strings num1 and num2 and two integers max_sum and min_sum. We denote an integer x to be good if:
- num1 <= x <= num2
- min_sum <= digit_sum(x) <= max_sum.
Return the number of good integers. Since the answer may be large, return it modulo 109 + 7.
Note that digit_sum(x) denotes the sum of the digits of x .
Example 1:
Input: num1 = "1", num2 = "12", min_num = 1, max_num = 8 Output: 11 Explanation: There are 11 integers whose sum of digits lies between 1 and 8 are 1,2,3,4,5,6,7,8,10,11, and 12. Thus, we return 11.
Example 2:
Input: num1 = "1", num2 = "5", min_num = 1, max_num = 5 Output: 5 Explanation: The 5 integers whose sum of digits lies between 1 and 5 are 1,2,3,4, and 5. Thus, we return 5.
Constraints:
- 1 <= num1 <= num2 <= 1022
- 1 <= min_sum <= max_sum <= 400
解题思路
很经典的数位dp。现在要求的是在范围内的数字中,有多少个数字的各位之和在范围内。为此我们可以先求出中满足各位之和在范围内的数字个数,记作。再求出中满足各位之和在范围内的数字个数,记作。那么答案就是。
而对于任意数字,如何求出中满足各位之和在范围内的数字个数呢?一样用到数位dp。先求出中各位之和不超过的数有多少个,记作。再求出中各位之和不超过的数有多少个,记作。那么中满足各位之和在范围内的数字个数就是。
因此最终答案就是。
定义状态表示所有长度为,且最高位为数字,各位之和不超过的数的集合。根据次高位是哪个数字进行状态划分,因此状态转移方程就是
这里用递推的方式来dp。现在求中各位之和不超过的数有多少个。从最高位往底位枚举(从开始),假设当前枚举到第位数字,并且第位的数字之和为,那么先累加所有长度为,第位是且各位之和为的数的个数,即。以此类推。当在枚举的过程中发现,那么直接返回答案即可。如果枚举完最后的,那么答案加,因为也满足要求。
这样做的计算量为,其中是数字的位数,是各位之和的最大值。如果这样做的话在leetcode会超时,估计卡常了。注意到最大为,因此最大为(所有的数都是的情况),为此我们可以让放小,令,这样就可以减低计算量了,变成。
AC代码如下:
1 class Solution { 2 public: 3 int mod = 1e9 + 7; 4 5 int count(string num1, string num2, int min_sum, int max_sum) { 6 function<int(string, int)> get = [&](string s, int x) { 7 if (s == "0") return 1; // 特判0的情况 8 int n = s.size(); 9 x = min(x, 9 * n); 10 vector<vector<vector<int>>> f(n + 1, vector<vector<int>>(10, vector<int>(x + 1))); 11 for (int i = 0; i <= 9; i++) { 12 for (int j = i; j <= x; j++) { 13 f[1][i][j]++; 14 } 15 } 16 for (int i = 2; i <= n; i++) { 17 for (int j = 0; j <= 9; j++) { 18 for (int k = j; k <= x; k++) { 19 for (int u = 0; u <= 9; u++) { 20 f[i][j][k] = (f[i][j][k] + f[i - 1][u][k - j]) % mod; 21 } 22 } 23 } 24 } 25 int ret = 0, sum = 0; 26 for (int i = 0; i < n; i++) { 27 int t = s[i] - '0'; 28 for (int j = 0; j < t; j++) { 29 ret = (ret + f[n - i][j][x - sum]) % mod; 30 } 31 sum += t; 32 if (sum > x) break; // 前面各位之和已经超过x 33 } 34 if (sum <= x) ret++; // num满足各位之和不超过x 35 return ret; 36 }; 37 // 因为要求num1-1,因此对num1进行减1 38 reverse(num1.begin(), num1.end()); 39 for (int i = 0; i < num1.size(); i++) { 40 if (num1[i] - 1 >= '0') { // 不需要借位 41 num1[i]--; 42 break; 43 } 44 num1[i] = '9'; // 借位 45 } 46 while (num1.size() > 1 && num1.back() == '0') { // 把前导0删除,同时要至少保留一位数 47 num1.pop_back(); 48 } 49 reverse(num1.begin(), num1.end()); 50 return ((get(num2, max_sum) - get(num2, min_sum - 1) + mod) % mod - (get(num1, max_sum) - get(num1, min_sum - 1) + mod) % mod + mod) % mod; 51 } 52 };
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17455885.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效