欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

剑指offer JZ31 整数中1出现的次数 Python 解

程序员文章站 2022-05-21 10:50:23
一.题目描述求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。二.解题思路1.暴力法:从1~n迭代,计算每个数字中1的数量然后累加。复杂度应该是 O(NlgN)2.归纳法:2.1简单来说,分别归纳个位,十位和百位上1的出现次...

一.题目描述

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

二.解题思路

1.暴力法:从1~n迭代,计算每个数字中1的数量然后累加。复杂度应该是 O(NlgN)

2.归纳法:

2.1

简单来说,分别归纳个位,十位和百位上1的出现次数,然后累加。

2.1部分来自牛客网用户id Duqcuiq讲解,2.2参考牛客网。

链接:https://www.nowcoder.com/questionTerminal/bd7f978302044eee894445e244c7eee6
来源:牛客网
 

个位

我们知道在个位数上,1会每隔10出现一次,例如1、11、21等等,我们发现以10为一个阶梯的话,每一个完整的阶梯里面都有一个1,例如数字22,按照10为间隔来分三个阶梯,在完整阶梯0-9,10-19之中都有一个1,但是19之后有一个不完整的阶梯,我们需要去判断这个阶梯中会不会出现1,易推断知,如果最后这个露出来的部分小于1,则不可能出现1(这个归纳换做其它数字也成立)。

我们可以归纳个位上1出现的个数为:

n/10 * 1+(n%10!=0 ? 1 : 0)

十位

现在说十位数,十位数上出现1的情况应该是10-19,依然沿用分析个位数时候的阶梯理论,我们知道10-19这组数,每隔100出现一次,这次我们的阶梯是100,例如数字317,分析有阶梯0-99,100-199,200-299三段完整阶梯,每一段阶梯里面都会出现10次1(从10-19),最后分析露出来的那段不完整的阶梯。我们考虑如果露出来的数大于19,那么直接算10个1就行了,因为10-19肯定会出现;如果小于10,那么肯定不会出现十位数的1;如果在10-19之间的,我们计算结果应该是k - 10 + 1。例如我们分析300-317,17个数字,1出现的个数应该是17-10+1=8个。

那么现在可以归纳:十位上1出现的个数为:

  • 设k = n % 100,即为不完整阶梯段的数字
  • 归纳式为:(n / 100) * 10 + (if(k > 19) 10 else if(k < 10) 0 else k - 10 + 1)

百位

现在说百位1,我们知道在百位,100-199都会出现百位1,一共出现100次,阶梯间隔为1000,100-199这组数,每隔1000就会出现一次。这次假设我们的数为2139。跟上述思想一致,先算阶梯数 * 完整阶梯中1在百位出现的个数,即n/1000 * 100得到前两个阶梯中1的个数,那么再算漏出来的部分139,沿用上述思想,不完整阶梯数k199,得到100个百位1,100<=k<=199则得到k - 100 + 1个百位1。

那么继续归纳百位上出现1的个数:

  • 设k = n % 1000
  • 归纳式为:(n / 1000) * 100 + (if(k >199) 100 else if(k < 100) 0 else k - 100 + 1)

后面的依次类推....

再次回顾个位

我们把个位数上算1的个数的式子也纳入归纳式中

  • k = n % 10
  • 个位数上1的个数为:n / 10 * 1 + (if(k > 1) 1 else if(k < 1) 0 else k - 1 + 1)

完美!归纳式看起来已经很规整了。 来一个更抽象的归纳,设i为计算1所在的位数,i=1表示计算个位数的1的个数,10表示计算十位数的1的个数等等。

  • k = n % (i * 10)
  • count(i) = (n / (i * 10)) * i + (if(k > i * 2 - 1) i else if(k < i) 0 else k - i + 1)

 2.2 另一种理解

假设我们从右至左分别计算每一位上1的个数,

简单来说,比如我想求某一位上1的个数,很显然它受到到高位和低位的影响。

1.如果该位(我要求的这位)值为0,那么该位1的个数仅受高位的影响,1个数 count=高位数*当前位数,(可以这样理解,前面的高位数是当当前位位1的时候,高位可以有多少种可能,与当前位数相乘是因为只要当前位位1,低位数不管是什么数都okay)

比如1204,对于十分位来说,它1个个数位12*10=120,比如 11,21,...1111,1211等。

2.如果该位之为1,该位1的个数为:高位数*当前位数+低位数。因为当前位为1的时候,低位数不管是啥数都okay,比如12123,

只要前面是121,后面低位数是啥都满足百位数为1.

3.如果该位为2~9,和情况1类似,仅由高位数决定,因为2~9大于1,所以要多加一个当前位数,比如12323,百位上3大于1,其实是包含了121XX的情况。此时count=(高位数+1)*当前位数。

三.源码

# 1 暴力
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        def calculateOne(num):
            rst=0
            while num:
                rst+=num%10==1
                num/=10
            return rst
        rst=0
        return sum([calculateOne(i) for i in range(n+1)])

# 2 归纳
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        i,rst=1,0
        while i<=n:
            # 小优化,if判断改成min max
            rst+=n/(10*i)*i+min(max(n%(i*10)-i+1,0),i)
            i*=10
        return rst

 

 

 

本文地址:https://blog.csdn.net/CSerwangjun/article/details/107246167