题目描述:
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
分析:
找规律。
该数字(不包括该数)以内 | 出现1的次数 |
1 | 0 |
10 | 1 |
100 | 20 |
1000 | 300 |
2 | 0+1+0=1 |
20 | 1+10+1=12 |
200 | 20+100+20=140 |
2000 | 300+1000+300=1600 |
3 | 1+0=1 |
30 | 12+1=13 |
300 | 140+20=160 |
m*10^i这个数(不含这个数):
如果m=1,那么这个数以内有(m*i*10^(i-1))个1。
如果m>1,那么这个数以内有(m*i*10^(i-1)+10^i)个1。
那么如果给出一个数,我们可以拆分每一位。
例如给出的数是1213的话,那么我们可以求
1000以内1的个数+200以内1的个数+10以内1的个数+3以内1的个数,
另外我们还需要加上213再加上3,因为它们的前一个位数字都是1;而且我们还要再加上2,因为本身1213中有2个1,我们之前算的一直都是不含本身的。
更加直观的讲就是,1213,求0~999中1的个数+1000~1199中1的个数+1200~1209中1的个数+1210~1212中1的个数+1213中1的个数。
213从1000~1199、1200~1209、1210~1212中的第一个1来的。
3从1210~1212中的第三个1来的。
代码:
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n) {
int n1 = n;
int i = ; // 0的个数
int ei = ; // 10^i
int ans = ;
while(n1) {
int m = n1 % ; // 首位
ans += m * i * ei / ;
if(m > ) ans += ei;
if(m == ) ans += n % ei + ;
ei *= ;
i++;
n1 /= ;
}
return ans;
}
};