题目:
输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。
例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
假如需要求的N=23106,那么计算过程如下:
万位=1:1 0000--1 9999 共计10000个
千位=1: 0 1 000--2 1 999 共计3*1000 = 3000,其中3表示万位可以填0,1,2三种情况,1000表示后面三位有000-999共1000种可能,所以总共可有3000种可能
百位=1:这里的可能情况并不是:00 1 00--23 1 99,因为最大只能到23106,所以我们可以把总和分为2部分:
00 1 00--221 99:共计23*100种,其中23表示万千位可以取00-22,23种可能,100表示十个位可以取00-99,100中可能。
23 1 00--231 06:共计7种,即万千位都固定,只有23一种情况,十个位可以取00-56,共57种可能
所以百位为1的数字数目,有2300+7 = 2307种;
十位=1:000 1 0--230 1 9 共计231*10=2310种,其中231表示万千百位可以取000-231,232种可能,而10表示个位可以去0-9十种可能。
因为以23110>23106,所以万千百位=231,且十位=1的数字数目为0
个位=1:0000 1--2310 1 共计2311*1种
所以总计数目:10000+3000+2307+2310+2311 = 19928种可能。
不失一般性,如果一个五位数字: abcde(ab肯定不等于0),如果我们想计算c = 1的数字有多少个,可以分以下情况讨论:
c >1: 00 1 00 -- ab 1 99,共计 (ab+1)*100种,其中(ab+1)表示万千位可以取00-ab,共计ab+1种。因为c>1所以 ab199<abcde,所以这些数都是在1 -- abcde范围内。
c=0: 00 1 00 -- a (b-1) 1 99, 总共有ab*100种,而a(b-1)200-ab099之间,都没有百位=1的数字出现了。
c=1: 我们可以把c = 1的数字分成以下2种情况之和
00 1 00 -- a(b-1)1 99 :总共ab * 100种可能性;
a(b-1) 2 00 -- ab 0 99:这段数字中百位=1的的数字数目为0;
ab 1 00 -- ab 1 cd:共计cd+1种可能性;
所以c =1的数字数目,等于c=0的数字数目,加上abcde%100 +1。
所以我们只要对每一位进行如上所示的讨论,得到这一位数字=1的数字数目,然后累计起来,就可以得到题目锁求问题的答案。
#include <iostream>
using namespace std;
int num_of_1(int n)
{
/*it should cover all powers of 10 within int range*/
int pow1 = 1;
int pow2 = 10*pow1;
int count = 0;
while(n >= pow1){//
int pow2 = 10*pow1;
switch( (n % pow2) / pow1){
case 0:
count += (n / pow2) * pow1;
break;
case 1:
count += (n / pow2) * pow1;
count += n % pow1 + 1;
break;
default:
count += (n / pow2 + 1) * pow1;
}
pow1 *= 10;
}
return count;
}
int main()
{
cout << num_of_1(12) << endl;
getchar();
return 0;
}