LeetCode Algorithms 233. Number of Digit One 题解
来源:互联网 发布:wow7.0优化 编辑:程序博客网 时间:2024/06/05 14:07
题目:Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.
题目意思就是求前n个非负整数里面出现1的次数
显然可以从0遍历到n,然后每个数字都求一次1的次数这样来解决,这是一个O(n)的解决方案,算不上很慢,但是看起来就觉得这是最差的方法。
通过观察可以发现,当我们按位数的个数来划分时,
- 位数是1时是
0-9
,1的个数为1,记为a1
; - 位数是2时是
10-99
,1的个数为10+a1+8xa1=19
,记为a2
; - 位数是3时是
100-999
,1的个数为100+a1+a2+8x(a1+a2)=280
,记为a2
; - ……
这里解释一下位数是2时是怎么数1的:
因为是数1,所以
10-19
首先包含十位数的10个1,数完这10个十位数的1后,把10-19看成0-9
来数(不需要再数十位数的1),即a0,然后20-99
,因为十位数都不是1,所以全部看成0-9
来数,共8个a0,加起来就是10+a0+8xa0=19
。同理,位数是3时,100-199有100个1,然后看成0-99来数,这个刚刚已经数过了是a1+a0,而200-999,因为百位数不是1,全部看成0-99来数,共8x(a1+a0)。
因为是求和,用an做记号不方便,设Sm=a0+a1+……+am,其中a0表示n<0时,且a0=0,那么:
- 位数是1时,1的个数为
S1
; - 位数是2时,1的个数为
S2
; - ……
- 位数是m时,1的个数为
Sm
;
根据前面的观察,写出Sm的递推式子: Sm=10^(m-1)+(a0+a1+...+a(m-1))+8x(a0+a1+...+a(m-1))+(a0+a1+...+a(m-1))
,
其中最后一项(a0+a1+...+a(m-1))
表示加上位数更小的结果,这样才算完整的0-999...99(m个9)
的1的个数。化简Sm后:
Sm=10^(m-1) + 10Sm-1
,求得:
Sm=m10^(m-1)
,到这里我们可以轻松的得到前n=999…999个非负整数的1的个数,显然这样是不够的,n可以是任意非负整数,比如n=23。面对这种情况,我们模仿Sm的推理过程,把23分成0-9,10-19,20-23这三段来计算,那么n=23时,1的个数={0-9}S1
+{10-19}10^1+S1
+{20-23}(2-2)xS1+S1
=13,
可见需要用到每个位数上的数字,因此使用一个数组N保存每个位数上的数字,对于一个m
位的n
,
n=N[0]+10N[1]+...+10^(m-1)N[m-1]
,从最高位开始,每一个位数以及后面的数字当成一段来计算,这样第i
段的1的个数可以写为:
S(m-1)+10^(m-1)+(N[i]-1)xS(m-1)
,计算完这段之后把该位置0,
这里需要注意两点:
1. 当N[i]=1时,不能直接计算10^(i-1),因为没有包含10…0-19…9中所有整数,这里
10^(m-1)+(N[i]-1)xS(m-1)
需要换成数字1后面的那串数字+1(比如123,就是换成23+1),然后进行下一段的计算。 2. 当N[i]=0时,应该跳过然后进行下一段的计算。
把以上算法写成代码如下:
int countDigitOne(int n) { /* S(n) = 10 * (10^(n - 2) + S(n-1)) where S(n) is the sum of 1 of the number of n digits and it follows that S(0) = 0 digits S(1) = 1 ... S(n) = n * 10^(n - 1) */ if (n <= 0) return 0; if (n < 10) return 1; int res = 0; int tmp = n; int digits = 0; // digits of n vector<int> S; // Sn vector<int> N; // N[i] represents the number of (i - 1) digit while (tmp) { N.push_back(tmp % 10); tmp /= 10; S.push_back(digits++ * pow(10, digits - 1)); } while (!N.empty()) { if (N.back() == 0) { N.pop_back(); continue; } res += S[N.size() - 1]; if (N.back() > 1) { int m = N.size() - 1; res = res + pow(10, m) + (N.back() - 1) * S[m]; // S[m] + (m - 2) * S[m] n -= N.back() * pow(10, N.size() - 1); } else { res = res + (n -= N.back() * pow(10, N.size() - 1)) + 1; } N.pop_back(); } return res;}
- LeetCode Algorithms 233. Number of Digit One 题解
- LeetCode 题解(148): Number of Digit One
- LeetCode题解——Number of Digit One
- LeetCode No.233 Number of Digit One 题解
- [leetcode] 233.Number of Digit One
- [LeetCode]233.Number of Digit One
- [leetcode] 233. Number of Digit One
- leetcode 233. Number of Digit One
- [LeetCode]233. Number of Digit One
- LeetCode 233. Number of Digit One
- leetcode.233. Number of Digit One
- LeetCode-233.Number of Digit One
- 233. Number of Digit One leetcode
- [LeetCode]233. Number of Digit One
- 【LeetCode】233. Number of Digit One
- Leetcode 233. Number of Digit One
- leetcode 233. Number of Digit One
- [leetcode]233. Number of Digit One
- Linux下ME3760_v2驱动移植方式,中兴4G网卡移植
- 几种常见数据预处理的效果图
- 机器学习算法实现解析——libFM之libFM的训练过程概述
- [YTU]_2624( B 结构体--统计投票)
- Neither BindingResult nor plain target object for bean name 'sqmy' available as request attribute
- LeetCode Algorithms 233. Number of Digit One 题解
- eclipse安装maven时,pom.xml提示报错
- bzoj 2434: [Noi2011]阿狸的打字机 AC自动机+树状数组
- Zynq Emacps Linux Driver
- kivy textinput弹出输入框处理
- 设计模式学习:工厂模式
- springboot的三种启动方式
- 使用SfntTool制作字体剪辑工具1
- ssM框架简单配置文件