求从1到n的正整数中1出现的次数

来源:互联网 发布:虚拟机mac os x 10.11 编辑:程序博客网 时间:2024/05/16 14:10

题目:输入一个数字n,求从1到n的正整数出现的次数。

例如:输入13,则包含1的数字有 1 10 11 12 13 这5个数,但是1出现的次数为6次。再比如输入29,则1出现1 10-19 21 这些数字,1共出现可知为13个。

本题目据说是google的一到面试题,刚开始思路有了,到最后完整实现用了一定时间。

最容易想到的方法:遍历,将所有1到n的数字都拿来遍历一边,计数1出现的次数。如果在面试的时候,采用此方法,肯定会被pass掉的。

接下来就是寻找规律,可以发现个位数里面只有1 出现1, 十位数中中内10-19这几个数字都有1,但是其他的20-29,30-39,,,90-99每个里面只有1个1。所有十位数中1出现的总和是20个。可以知道十位数的个位上出现10次,十位上出现10次。于是所有N位数出现1的个数可以通过如下递归函数得到。

def funit(width):    if width == 1:        return 1    else:        return 10 ** (width - 1) + 10 * funit(width -1)

从上面的函数计算可以funit(1) =1 , funit(2)=20, funit(3)=300,这些数字都是对应所有的位数,相当于9,99,999内1的个数为1 20 300。

如果我们那654举例子,百位上肯定会出现10^2共100此,十位上会出现10^1 + 6*funit(2)共计6*20+10=130次,个位上出现10^0+5*funit(1)共6次,最后可知100+130+6=236次。

所以计算的公式应该为f(x) = 10**(width(x)-1) + x[0]*funit(width(x)-1) + f(x[1:])

特别需要注意的是当出现1的时候,比如125,实际百位上出现了(125-100)+1 = 26次,但是上面公司第一项得到的是10**2=100,所以遇到1需要特殊处理。

十位上出现1的时候,也需要特别处理,比如10中1的出现次数为2,11次数为4,12次数为5, 依次类推,当数字大于11后1出现的次数为个位数+3,见下面的函数。

def special(bit):    if bit == '10':        return 2    elif bit == '11':        return 4    else:        return int(bit[1]) + 3

有了以上分析,最后求1出现的次数的实现为:

def get_countof1(bit):    test = str(bit)    if len(test) == 1:        if bit >= 1:            return 1        else:            return 0    if len(test) == 2:        if test[0] == '1':            return special(test)        else:            return 10 + int(test[0])*funit(1) + get_countof1(int(test[1]))    else:        if test[0] == '1':            sure_count = 1 + int(test[1:])        else:            sure_count = 10 ** (len(test) - 1)        return sure_count + int(test[0])*funit(len(test)-1) + get_countof1(int(test[1:]))

附:循环遍历的代码:

def get_traverse(number):    sum = 0    for i in xrange(number+1):        temp = str(i)        for j in xrange(len(temp)):            if temp[j] == '1':                sum += 1    return sum

简单测试:

本人写的太啰嗦了,其实就是找规律递归,速度肯定快很多。可以粗略估计循环计算时间复杂度为O(width(n)*n), 而采用递归计算复杂度应该为0(c) c只与width(n) 有关。可以认为是个常量。看看对如下几组数据的测试结果。如果采用循环,如第二个表。

测试数据递归结果用时(real)9876545953360m0.159s987654369410150m0.153s98765432792866940m0.158s9876543218916323730m0.169s

测试数据循环结果时间(real)9876545953360m1.129s987654369410150m12.750s98765432792866942m13.896s98765432189163237325m15.260s

原创粉丝点击