1的数目

来源:互联网 发布:xp网络共享文件夹 编辑:程序博客网 时间:2024/04/29 18:57

看编程之美第一天~先来记记这算法第一题

1的数目

给出一个十进制正整数N,算出从1到N出现的所有'1'的数目。

 

初一看来,很简单嘛,遍历一下就完了~效率啊效率,不解释

先写写自己做的,也就是编程之美第一种解法:

对每一个数遍历含有1的数目加起来,这种应该算是学过编程的人都会做吧

但是这种情况我们可以算下时间复杂度:

首先遍历每个数的位数的时间复杂度,设a/=10;执行f(n)次,则10^f(n)<n,得时间复杂度O(log2 n)

再对于遍历从1到N的数是O(n),最后整个算法时间复杂度为O(n*log2 n)

根据编程之美所说一样,如果计算100 000 000的1的数目,计算时间大概需要40秒

下面来说说第二种解法:

既然遍历效率太低,那根据规律来判断吧

 

首先从一位数来看

一位数时,无论怎样看只要大于0只可能出现一次1

 

再看两位数

如果十位数是大于1的数,在十位会出现1的情况就只有10到19,在个位会出现1的情况就是1,11,21等等

这个地方我们可以注意一下了,个位出现1的总数是取决于十位数是多少,还取决于本身是多少。

比如如果N是20,个位出现1的总数只有1和11;而如果N是21到29,则个位出现1的总数有1,11和21。

如果十位数是1,则在十位会出现1的情况数还取决于个位数为多少的,比如如果个位数为2则十位数上出现1的情况只有10,11和12。

以此类推。

最后算出来结果便是十位上出现1的情况和个位上出现1的情况总数相加。

 

再来看三位数

如果百位数是大于1的数,在百位会出现1的情况就有100到199这100个数;如果百位数为1,则在百位会出现1的情况是取决于十位和个位为多少的,比如123,在百位出现1的情况数只有100到123。百位数情况先讨论至此。

这里我们需要注意十位数。如果十位数是大于1的数,十位数上会出现1的情况是取决于比他更高位的,比如220,此时在十位会出现1的情况有10到19,110到119和210到219,也就是百位从0到当前百位数值,3*10。

如果十位数是1,则十位数上会出现1的情况不仅取决于高位还取决于低位的数值。比如211,此时在十位会出现1的情况有10到19,110到119和210到211,也就是百位从0到当前百位数值减一,2*10,还得加上百位为2时的2种情况,也就是低位数值加1。

如果十位数是0,则十位数上会出现1的情况只取决于高位,比如N为201,此时在百位数为2时十位不可能为1,也就是2*10。

此时个位同样如果大于1,则在个位可能出现1的情况取决于高位,比如112.,个位可能出现1的情况有1,11到91,101,111,为(11+1)*1

如果个位为1,如111,则可能情况为1,11到91,101,111,为(11+1)*1+0。读者应该能理解我为什么要加一个0在后面。

如果个位为0,如110,则可能情况为1,11到91,101,为11*1。

 

四位数以及更多位数读者可自行验证。

经过这样推导,不难理解每一位上出现1的情况数分为三种情况:

一、如果给出的N当前位大于1时,在当前位可能出现1的情况中,总数取决于更高位,其可能情况数位高位值加一乘以当前位幂

二、如果给出的N为1,则当前位可能出现1的情况取决于高位和低位,可能情况数位高位值乘以当前位幂再加低位加1的值。

三、如果给出的N为0,则出现的情况比第一种情况少了高位为最大时的情况。

给粗心的人提示下~high*flag的值并不等于b/10的哈。