题目描述:
输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:输入:n = 13
输出:6
限制:
1 <= n < 2^31
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:这道题没什么难的,就是麻烦,麻烦,麻烦。。。。而且可以说是一道找规律的题。我用到了递归。
先设定函数countbase,用来计算1,10,100,1000。。。即10的整数幂次中1的个数
例如,countbase(10)为0-9中1的个数,countbase(1)为1中的1个数。
由题意得,假定对于147来说,我们计算它的1的个数
num(147)= 1*countbase(100)+48+4*countbase(10)+10+countbase(1),
其中:
1*countbase(100):代表的是0-99中,所有个位,十位上1的个数
48:代表100-147中,百位上的48个1
4*countbase(10):代表的是0-9、10-19、20-29、30-39中,所有个位上(不包括十位)上1的个数
10:代表10-19中,十位上的10个1
countbase(1):代表的是40-47中,所有个位上1的个数
对于2444来说
num(2444)= 2*countbase(1000)+1000+4*countbase(100)+100+ 4*countbase(10)+10+ 1*countbase(1)
2*countbase(1000):代表0-999,1000-1999中,所有个位,十位,百位(不包括千位)上1的个数
1000:代表1000-1999中,千位上的1000个1
4*countbase(100):代表0-99,100-199,200-299,300-399中,所有个位,十位(不包括百位)上1的个数
100:代表100-199中,百位上的100个1
4*countbase(10):代表的是0-9、10-19、20-29、30-39中,所有个位上(不包括十位)上1的个数
10:代表10-19中,十位上的10个1
countbase(1):代表的是40-44中,所有个位上1的个数
这样的话,就能写出代码:
class Solution {
public:
int countDigitOne(int n)
{
// sum代表所有1的总和
unsigned long long int sum=0;
// res存储base中所有1的和
// 以147为例,则res依次存储0-99,0-9的所有1的和
// 以2444为例,则res依次存储0-999,0-99,0-9的所有1的和
unsigned long long int res=0;
// base从1开始,依次为10,100,1000。。。直到比n小的最大10的整数幂
// 例如,n=147,那么base最大到100,n=2444,base最大到1000
unsigned long long int base=1;
// base<=n时循环
while(base<=n)
{
// 在base没到达比n小的最大10的整数幂之前,用res记录base=1,10,100。。。中所有1的和
res=countbase(base-1);
if(n>=base&&n<base*10)
{
// base已经到最大了,开始计算有多少个base
// 例如,n=147,则只有1个base,n=2444,则有2个base
// left代表n的最高位
int left=n/base;
if(left>1)
{
// 如果最高位>1,那么就有n个base的1要加上
res=res*left;
// 并且最高位上还有base个1
// 例如,n=2444,最高位left=2,base=1000,则2444之前,0-2000中含有两个base的1,而且在第二个base中,left所在的最高位,1出现了1000次(base次),即1000-1999中,千位上的1出现了1000次
res=res+base;
}
else if(left==1)
{
// 如果最高位left==1
res=res*left;
// right代表除了最高位的其他数字,例如n=147,left=1,right=47
unsigned long long int right;
if(n>=10)
right=n%base;
else
right=0;
// 加上最高位上right+1个数字1
// 例如n=147,要加上100-147中百位上的47+1=48个数字1
res=res+right+1;
}
// sum加上res,保存好
sum+=res;
// 最高位处理完后,处理下一位。例如n=2444,千位上的1处理完之后,开始处理百位244中的数字1个数
n=n%base;
// base重新从1开始
base=1;
continue;
}
base=base*10;
}
return sum;
}
// 递归,来计算1,10,100,1000。。。。中的1的个数
unsigned long long int countbase(unsigned long long int n)
{
if(n==0)
return 0;
if(n>=1&&n<=9)
return 1;
else
return countbase(n/10)*10+n/10+1;
return 0;
}
};