经典算法: 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数

题目:

输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。

例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。

假如需要求的N=23106,那么计算过程如下:

万位=11 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;  
}  




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值