输入任意一个数,得到1到这个数之间的1的个数

好久没写博客了,忙着面试,现正学习各种算法,今天碰到一个题。就是题目所写的那样,输入任意一个数,得到1到这个数之间的1的个数。比如这个数是12,那么函数f(12)返回的是5(因为中间有5个1)。

另外说明一下,由于个人水平有限,算法的效率有待提高,欢迎高手指点。

当$num=100000000时,代码大概执行了50秒,并且是在修改了30秒运行超时的错误和内存溢出的错误之后,说明代码的问题很大,应该优化php代码。

仔细分析这个问题,给定了N,似乎就可以通过分析"小于N的数在每一位上可能出现 1 的次数"之和来得到这个结果让我们 来分析一下对于一个特定的  N,如何得到一个规律来分析在每一位上所有出现 1 的可能性,并求和得到最后的 fN)。

先从一些简单的情况开始观察,看看能不能总结出什么规律。

先看 1 位数的情况。

如果 N  =  3,那么从 1 3 的所有数字:123,只有个位数字上可能出现 1,而且只出现 1 次,进一步可以发现如果 N 是个位数,如果 N>=1,那么fN)都等于 1,如果 N=0,则 fN)为 0

再看 2 位数的情况。

如果 N=13,那么从 1 13 的所有数字:123456 78910111213,个位和十位的数字上都可能有 1,我 们可以将它们分开来考虑,个位出现 1 的次数有两次:1 11,十位出现 1 的次数有 4 次:101112 13,所以 fN=2+4=6。要注意的是 11 这个数字在十位和个位都出现了 1,但是 11 恰好在个位为 1 和十位为 1 中被计算了两次,所以不用特殊处理,是对的。再考虑 N=23 的情况,它和 N=13 有点不同,十位出现 1 的次数为 10 次,从 10 19,个位出现 1 的次数为 111 21,所以fN=3+10=13。通过对两位数进行分析,我们发现,个位数出现 1 的次数不仅和个位数字有关,还和十位数有关:如果 N 的个位数大于等于 1,则个位出现 1 的次数为十位数的数字加 1;如果N 的个位数为 0,则个位出现 1 的次数等于十位数的数字。而十位数上出现  1 的次数不仅和十位数有关,还和个位数有关:如果十位数字等于 1,则十位数上出现 1 的次数为个位数的数字加 1;如果十位数大于 1,则十位数上出现 1 的次数为 10

f(13) = 个位出现1的个数 + 十位出现1的个数 = 2 + 4 = 6

f(23) = 个位出现1的个数 + 十位出现1的个数 = 3 + 10 = 13

f(33) = 个位出现1的个数 + 十位出现1的个数 = 4 + 10 = 14

...

f(93) = 个位出现1的个数 + 十位出现1的个数 = 10 + 10 = 20

接着分析 3 位数.

如果 N = 123

个位出现 1 的个数为 131, 11, 21, ¼, 91, 101, 111, 121

十位出现 1 的个数为 201019, 110119

百位出现 1 的个数为 24100123

f23=  个位出现 1 的个数  +  十位出现 1 的个数  +  百位出现 1 的次数  = 13 + 20 + 24 = 57

同理我们可以再分析 4 位数、5 位数。读者朋友们可以写一写, 总结一下各种情况有什么不同。

根据上面的一些尝试,下面我们推导出一般情况下,从 N 得到 fN)的计算方法:

假设 N=abcde,这里 abcde 分别是十进制数 N 的各个数位上的数字.如果要计算百位上出现  1 的次数,它将会受到三个因素的影响:百位上的数字,百位以下(低位)的数字,百位(更高位)以上的数字。

如果百位上的数字为 0,则可以知道,百位上可能出现 1 的次数由更高位决定,比如 12 013,则可以知道百位出现 1 的情况可能10019911001 19921002199¼11100~11199,一共有 1200 个。也就是由更高位数字(12)决定,并且等于更高位数字(12×当前位数(100).

如果百位上的数字为 1,则可以知道,百位上可能出现 1 的次数不仅受更高位影响,还受低位影响,也就是由更高位和低位共同决定。例如对于 12113,受更高位影响,百位出现 1 的情况是 1001991100119921002199¼11100~11199,一共 1200个,和上面第一种情况一样,等于更高位数字(12×当前位数(100但是它还受低位影响,百位出现 1 的情况是 12 10012 113,一共114 个,等于低位数字(123+1如果百位上数字大于  1(即为  2~9),则百位上可能出现1的次数也仅由更高位决定,比如 12 213,则百位出现 1 的可能性为:1001991 1001 1992 1002 199¼11 10011 19912 10012 199,一共有 1 300 个,并且等于更高位数字+112+1 ×当前位数(100).

通过上面的归纳和总结,我们可以写出如下的更高效算法来计算 fN):

这个函数还有点瑕疵,返回的结果不对貌似,希望高手指点一下。

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hankmiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值