文章标题
来源:互联网 发布:出租屋网络千兆方案 编辑:程序博客网 时间:2024/06/07 14:53
这道题目与leetcode 600 有一些相似, 所以博主一开始用的是相类似的解法. dp[n][i]记录的是位数<=n的数中, 包含i个1的数的个数.
1. dp[n][0] = dp[n-1][0] + 8*dp[n-1][0] = dp[n-1][0] * 9.
其中, 第一部分表示位数<=n-1的数中, 包含0个1的个数. 第二部分表示位数等于n的数, 包含0个1的个数. 第n位可以选择2, 3, …9这八个数.
2. dp[n][i] = dp[n-1][i] + dp[n-1][i-1] + 8*dp[n-1][i]
其中第一部分表示位数小于等于n-1的包含i个1的数的数量. 第二部分表示位数为n, 且第n位为1. 则剩下的部分只要满足有[i-1]个1就可以了. 第三部分表示位数也是n位. 但是第n位选择2, 3, … 9
假设n的位数为N,在得到这个dp之后我们可以把问题拆解为两部分: 位数为N的数中包含的1数量. 位数小于N的数中包含的1的数量. 第二部分很好求:
for(int c = len-1; c>=1; --c) { cnt += dp[len-1][c]*c;}
zhzz至于第一部分, 因为必须<=n, 所以我们需要逐一位处理:
先处理小于n的数,
考虑第N位:
53144xxx3xxx2xxx1xxx第N位可以取4, 3, 2, 1
剩下的位:
531452xx51xx50xx第N-1可以取2, 1, 0
int countDigitOne(int n) { if(0 == n) { return 0; } int len = 1; long mask = 10; while(n >= mask) { ++len; mask *= 10; } vector<vector<int>> dp(len+1, vector<int>(len+1, 0)); dp[0][0] = 1; dp[1][0] = 9; dp[1][1] = 1; for(int l = 2; l <= len; ++l) { dp[l][0] = dp[l-1][0] * 9; for(int c = 1; c <= l; ++c) { dp[l][c] = dp[l-1][c] * 9 + dp[l-1][c-1]; } } mask /= 10; int cnt = 0; /*size = len*/ int prev_1_cnt = 0; for(int i = len; i >= 1; --i) { const int digit = n/mask; int not1_head = 0; if(i == len) { not1_head = digit - 2; }else if(digit == 1){ not1_head = 1; }else { not1_head = digit - 1; } if(not1_head >= 1) { for(int l = 0; l <= i-1; ++l) { cnt += not1_head * dp[i-1][l] * (prev_1_cnt+l); } } if(digit > 1) { for(int c = 0; c <= i-1; ++c) { cnt += dp[i-1][c] * (prev_1_cnt + c +1); } } n = n % mask; mask /= 10; if(digit == 1) { ++prev_1_cnt; } } /*size < len*/ for(int c = len-1; c>=1; --c) { cnt += dp[len-1][c]*c; } cnt += prev_1_cnt; return cnt;}
a前面的方法还是非常繁琐的. 这里再引入StefanPochmann 大神的解法
对于一个数. 我们计算能有多少个数个位上有1, 十位上有1, 百位上有1…把这些数都加起来就是我们要的结果:
a我们只分析百位上的情况:
n=3141592
31415920-3141|1|0-99总共有(3141+1)*100个数
n=3141192
31411920-3140|1|0-993141|1|0-91总共有3141*100 + 92个
能n=3141092
31410920-3140|1|0-99共有3141*100个
int countDigitOne(int n) { if(0 == n) { return 0; } long mask = 1; int cnt = 0; while(n >= mask) { const int a = n / mask; const int b = n % mask; const int v = a%10; if(v > 1) { cnt += (a/10 + 1) * mask; }else if(v == 1) { cnt += (a/10) * mask + b+1; }else { cnt += (a/10) * mask; } mask *= 10; } return cnt;}
阅读全文
0 0
- 文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题 文章标题 文章标题 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- Find The Multiple
- 欢迎使用CSDN-markdown编辑器
- 行业人员为你独家解密IT培训的几种模式
- Linux下33个常用的Find实例
- python 点滴学
- 文章标题
- javascript数组的定义及其属性和方法的使用
- 问题 E: 魔法扫帚
- 项目结题报告
- 外观模式
- 相关SCI期刊
- 三大牛人看外国文献的方法
- HTML第二天
- C