题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
解析:可以先计算最高位1的个数,然后再计算低位1的个数,找出规律。
情形 1.1 比如数22345可以分成两段, 10000 ~ 19999, 20000 ~ 22345。 当最高位为1时,即1xxxx, 此时最高位出现1的个数为 10^4。当最高位为2时,即2xxxx,此时最高位没有1。
情形 1.2 当数在 [10000, 20000), 如12345, 则最高位1出现的次数为 1 + 2345 = 2346次。
情形 2 考虑了最高位1 的个数后,接下来考虑低位1的个数。 如2xxxx这个数, 第二位为1时,其他位可以为1,也可以不为1,所以这是一个排列组合问题。总共有 4 x 10 ^ 3 个 1。 最高位又有两种选择, 所以 5 位数的情况总共出现的1 的个数为 2 x 4 x 10^3 次, 即 8000次。
通过分析5位数1 的个数,我们总结出了规律如下:
if 数abcde最高位为 1 : 则 最高位出现1 的个数 为 bcde + 1 次
else 数abcde最高位不为 1 : 则最高位出现1 的个数为 10 ^ 4 次
再加上低位出现的个数 a x 4 x 10 ^3 次即为五位数出现 1 的次数。
只要再递归此过程,求出四位数,三位数...1位数 出现 1个次数,求和就能直到所有数 出现 1 的次数。
python代码
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
if(n <= 0):
return 0
if( n < 10):
return 1
else:
res = 0
length = len(str(n))
# 求最高位
left = n // (10 ** (length - 1)) # 求最高位
right = n - left * (10 **(length - 1)) # 求 低位
# 统计最高位 1 的个数
if(left == 1):
res = (right + 1)
else:
res = (10 ** (length - 1))
# 统计低位 1 的个数
res += left * (length - 1) * (10 ** (length - 2 ))
return res + self.NumberOf1Between1AndN_Solution(right) # 递归