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

Solutions

最简单的方法就是遍历每个数,查看每个数中的1个数,有可能是 $O(n^2)$ 的复杂度:

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0
        for i in xrange(1, n+1):
            while i != 0:
                if i % 10 == 1:
                    count += 1
                i /= 10
        return count

在这种方法上还可以避免用除法和取余,可以用字符串,也能解决一定的时间:

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0
        for i in xrange(1,n+1):
            for j in str(i):
                if j == "1":
                    count += 1
        return count

第二种是用数字规律法。对于一个整数,逐位分析它上面出现1的次数,然后加起来。以百位为例。

  1. 若百位数字为0,比如12024,则百位上可能出现1的有:100~199,1100~1199,……,11100~11199,共12*100个,可见等于其高位数字*当前位数。
  2. 若百位数字为1,比如12124,则百位上可能出现1的有:100~199,1100~1199,……,11100~11199,12100~12124,共12*100+25个,可见等于高位数字*当前位数+低位数字+1。
  3. 若百位数字大于1,比如12224,则百位上可能出现1的有:100~199,1100~1199,……,11100~11199,12100~12199,共(12+1)*100个,可见等于(高位数字+1)*当前位数。
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        res = 0
        s = str(n)
        length = len(s)
        for idx, i in enumerate(s):
            place = length - idx  # 当前位数(个位是1,十位是2……)
            pre = n // (10 ** place)  # 当前位数的高位数字
            aft = n % (10 ** (place - 1))  # 当前位数的低位数字
            if i == '0':
                res += pre * 10 ** (place - 1)
            elif i == '1':
                res += pre * 10 ** (place - 1) + aft + 1
            else:
                res += (pre + 1) * 10 ** (place - 1)
        return res

References

  1. 032. 整数中1出现的次数