【题目】求出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