剑指offer——31整数中1出现的次数(Python)

【题目】求出1-13的整数中1出现的次数,并算出100-1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
【思路】暴力方法,将所有数字连成一个字符串,然后挨个遍历,判断是否为1,该方法处理较大的数字的时候时间复杂度较大,不推荐。
改良版:不连起来,从1到第n个数,逐个判断每个数里包含一的个数然后累加,也可将数字转化为字符串进行判断,也可直接对数字进行处理
【代码实现】

    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0
        for i in range(1,n+1):
            while i:
                if i%10 == 1:
                    count += 1
                i = i//10
        return count
   //转化为字符串
   def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0
        for i in range(1,n+1):
            s = str(i)
            for c in s:
                if c == '1':
                    count += 1
        return count

【推荐方法】数字是由1到n,拿到n之后通过对n的每一位上出现1的次数进行计算并叠加,即可得出最终1出现的次数。假设n是一个五位数12x45,此时要分析x取不同的值对最后结果的影响,分别是x<1(即x=0),x=1,x>1。逐个分析(x在百位上,下面的高位指千位,万位,低位指十位和个位):
当x=0,若要x的位置为1,则需要向高位借一个,此时x为1,低位有100种取法,即100-199,而高位被借了一位,只能取0-11这12个数,即百分位为0时,该位置出现1的数有高位数乘以位数,在这里为12(高位能取值的个数)×100(此时判断的位数)。
当x=1,此时无论高位是啥,低位是啥,都算作该位出现1的次数,所以时高位可以取的数0-12,13个数,低位有100种取值,即当百分位是1时,该位出现1的次数为13×100,但其实不然,因为在示例中,当前面取121时,后面最大的45,只能有0-45这46种可能,所以应该是12×100+46。
当x>1,此时高位就可以全部取到,且低位有100种可能,x45比199大,所以此时的总次数为13×100。
上述分析就得出1到n中,百位上出现1的总的个数,依次分析,相加即可得出最终的个数。
代码如下:

class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0 #总的次数
        digit = 1 #逐位去判断,初始为第一位
        while digit <= n:
            a, b = n/digit, n%digit
            #这里用的是python2,/表示地板除,整数除整数,没能整除返回整数,在python3中应使用//。
            #%表示取余,此处的a,b相当与例子中的12x和45
            count += (a+8)/10*digit + (a%10==1)*(b+1)
            #a+8是为了处理进位的情况,当x>1时,a+8就进一位了,另外两种情况均不需要进位。
            #a%10==1是用来判断x是不是等于1,如果等于1,则次数还需要加上b+1,详情见分析中x=1的情况。
            digit *=10 #对后面一位进行循环判断
        return count
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值