1到n的正数中1出现的次数

http://www.360doc.com/content/12/0317/18/1429048_195182735.shtml

http://www.cnblogs.com/python27/archive/2011/12/14/2288205.html

【题   目】输入一个整数n,求从1到n这n个正数中,1出现的次数。例如:输入12,出现一的数字有1,10,11,12共有5个1,则输出5.

【思 路2】上述算法的效率不是很好,尤其对于n非常大的情况,这种算法花费的时间很长。其实我们并不需要对于每一个数字计算出它包含的1的个数,我们可以逐位考虑,所有1的个数等于个位上1的个数+十位上1的个数+百位上1的个数+千位上1的个数+。。。接下来的问题,就是如何求解这些位上1的个数?

  首先,我们有如下比较容易得到的结论,0-9中1的个数是1个,0-99中十位(10-19)上1的个数是10,0-999中百位上(100-199)上1的个数是100,以此类推。为什么需要这些数字,我们经过简单罗列,很容易发现:个位上1的个数,实际上和这个数字包含多少个10有关,因为对于个位来说,总是从0-9循环,十位上1的个数,实际上和这个数字包含多少个100有关,因为每包含1个100,就有0-99的循环,而0-99中十位上的1是10个;那么关系究竟是什么呢?我们看下面的例子来理解:

  对于数字123:

  123/10=12,包含12个10,每个10包含1个1(个位1)所以个位共包含12*1=12个1;余数的情况后面单独讨论;

  123/100(或者12/10)=1,包含1个100,每个100包含10个1(十位1),所以十位共包含1*10=10个1;余数的情况后面单独讨论;

  123/1000(或者1/10)=0,包含0个1000,每个1000包含100个1(百位1),所以百位共包含0*100=0个1;余数的情况后面单独讨论;

  现在考虑余数的两种情况:

  (1)余数大于1的情况:

  数个位时,余数3大于1;所以个位上1的个数要+1;

  数十位时,余数2大于1;因为增加了100-120之间(10-19)的数字即110-119,所以十位上1的个数要+10;

  (2)余数等于1的情况:

  数百位时,余数等于1;我们应该增加100-123这24个数字中百位上的1,共计24个;

  在上面的计算中我们发现123/1000=0包含0个1000,所以百位包含0*100个1,这是常规的情况,实际上由于百位为1,从100到n(123)中还应增加:123-100+1个1.

  总结上面的情况:就是对于每一位(个位,十位,百位),我们计算他们“通常”情况下(即该数字包含多少个10,100,1000乘以对应的1的个数)包含的1的个数+该位上余数大于1(等于1)的情况下包含的1的个数 = 该位上1的总个数,所有的位遍历,求和,就OK了。根据这种思路我们可以得到如下的代码:

复制代码
 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 
 5 int NumbersOf1sFrom1ToN(unsigned int n)
 6 {
 7     int currentN = n;
 8     
 9     //计数器
10     int cnt = 0;
11 
12     //商,计算该数字包含多少个10,100,1000等
13     int quotient = 0;
14     
15     //余数,计算除去“整”的包含,剩下的数字包含的1的个数
16     int remainder = 0;
17     
18     //每一轮循环中的权重,分别记录10,100,1000中包含多少个位1,十位1,百位1;
19     int mult = 1;
20     
21     while(currentN)
22     {
23         quotient = currentN / 10;
24         remainder = currentN % 10;
25         
26         //包含多少个10,100,1000,乘以对应的数量的个位1,十位1,百位1
27         cnt += quotient * mult;
28 
29         //余数大于1,多加一个该轮下的权重
30         if(remainder > 1)
31         {
32             cnt += mult;
33         }
34         //余数等于1
35         else if(remainder == 1)
36         {
37             cnt += n - currentN * mult + 1;
38         }
39 
40         
41         currentN = currentN / 10;
42         mult *= 10;
43     }
44 
45     return cnt;
46 }
47 
48 int main()
49 {
50     cout<<"please enter the number N:"<<endl;
51     unsigned int number = 0;
52     cin>>number;
53 
54     cout<<"the number of 1s From 1 to N is:"<<endl;
55     cout<<NumbersOf1sFrom1ToN(number)<<endl;
56     
57     return 0;
58 }
复制代码

  运行结果如下:


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值