剑指offer JZ31 整数中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迭代,计算每个数字中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
推荐阅读
-
剑指offer31:整数中1出现的次数(从1到n整数中1出现的次数)
-
剑指offer11:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(进制转换,补码反码)
-
剑指offer JZ31 整数中1出现的次数 Python 解
-
剑指offer 56 数组中数字出现的次数 lintcode 82. 落单的数、83. 落单的数 II、84. 落单的数 III
-
【剑指offer】面试题56(1):数组中只出现一次的两个数字
-
剑指offer 面试题56 python版+解析:数组中只出现一次的两个数字,数组中唯一只出现一次的数字
-
【剑指Offer】 40.数组中只出现一次的数字 python实现
-
【剑指Offer】40. Python实现数组中只出现一次的数字
-
【剑指Offer】40.数组中只出现一次的数字(Python实现)
-
【剑指offer】_11整数中1出现的次数