题目:输入一个整数n,求从1到n这n个整数中的十进制表示中,1出现的次数。
分析:
我们用一个稍微大一点的数字21345作为例子来分析。我们把从1到21345的所有数字分成两段,即1-1345和1346-21345。
先来看1346-21345中1出现的次数。1的出现分为两种情况:一种情况是1出现在最高位(万位)。从1到21345的数字中,1出现在
10000-19999这10000个数字的万位中,一共出现了10000(104)次;另外一种情况是1出现在除了最高位之外的其他位中。例子中
1346-21345,可以分为1346-11345以及11346-21345这两段,每一段都是10000个数,两段也就是20000个数。先分析1346-11345这
10000个数,在这些数的后四位中实际上是从1346->1347...->9999->0->1->2...->1344->1345,这么一个过程,也就是说后4位实际上可以看成从0~9999这10000个数,其中1出现在每一位上有4中可能,然后剩下的3位可以从0~9随便取,从而一共有4*10^3个1,这只是1346-11345的,再加上11346-21345的,一共是2*4*10^3个1。也就是说1出现在除了最高位之外的其他位中总共出现的次数是最高位*其它位的位数(也就是len-1)*10^(len-2)。
至于从1到1345的所有数字中1出现的次数,我们就可以用递归地求得了。这也是我们为什么要把1-21345分为1-13455和1346-21345两段
的原因。因为把21345的最高位去掉就得到1345,便于我们采用递归的思路。
分析到这里还有一种特殊情况需要注意:前面我们举例子是最高位是一个比1大的数字,此时最高位1出现的次数104(对五位数而言)。但如果最高位是1呢?比如输入12345,从10000到12345这些数字中,1在万位出现的次数就不是104次,而是2346次了,也就是除去最高位数字之后剩下的数字再加上1。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int power(int n)
{
int result = 1;
int i;
for(i=0;i<n;i++)
result *= 10;
return result;
}
int numbers_core(const char *str)
{
if(str==NULL || *str<'0' || *str>'9' || *str=='\0')//字符串地址为空或者首字符不是0~9或者是空字符串,直接返回
return 0;
int first = *str - '0';//将首字符转换成整数
int len = strlen(str);//字符串的长度
if(len==1 && first==0)//判断n是不是0,如果是,则返回0
return 0;
if(len==1 && first>0)//判断n是不是1~9,即只有一位,如果是,则返回1
return 1;
int num_first_digit = 0;//用于记录最高位出现1的次数
int num_other_digit = 0;//用于记录除最高位之外的其它位出现1的次数
int num_cursive;//用于记录递归返回的次数
if(first==1)//如果最高位为1,则最高位出现1的次数是其它位加1,比如1234,则最高位1出现的次数是234+1
num_first_digit = atoi(str+1)+1;
else if(first>1)//如果最高位不是1,则最高位出现1的次数是剩下位数的10的幂次方,比如2234,最高位1出现的次数是10的三次方,即1000~1999
num_first_digit = power(len-1);
num_other_digit = first*(len-1)*power(len-2);//其它位出现1的次数
num_cursive = numbers_core(str+1);//从字符串最高位的下一位继续递归
return num_first_digit+num_other_digit+num_cursive;//返回的是记录最高位1的次数以及其它位为1的次数以及递归返回的次数之和
}
int numbers(int n)
{
if(n<=0)
return 0;
char str[50];
sprintf(str,"%d",n);//将n值转换为字符串
return numbers_core(str);
}
int main()
{
int n;
printf("请输入n的值:\n");
scanf("%d",&n);
int num = numbers(n);
printf("从1到%d中1出现的次数为:%d\n",n,num);
return 0;
}