《剑指offer》--- 整数中1出现的次数
本文算法使用python3实现
1. 问题
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
时间限制:1s;空间限制:32768K
2 思路描述
方法一:暴力解法(当数字较小时可以,数字很大时不可取)
方法二:观察规律(在此我们将题目拓展成整数中 $ X $ 出现的次数,$ X \in \lbrace 1,2,3,4,5,6,7,8,9 \rbrace $ )
(1)在 $ [1 , 10] $ 中 ,个位上 $ X $ 出现的次数为 $ 1 $ 。
(2)在 $ [11 ,100] $ 中,十位上 $ X $ 出现的次数为 $ 10 $ 。
(3)在 $ [101,1000] $ 中,百位上 $ X $ 出现的次数为 $ 100 $ 。
(4)以此类推,在 $ [10^i+1, 10^{(i+1)}] $ 上,从右数第 $ i $ 位上 $ X $ 出现的次数为 $ 10^{(i-1)} $ 。
而 $ [1,n] $ 中第 $ i $ 位上 $ X $ 出现的次数规律为:
(a)当第 $ i $ 位的数字 $ >X $ 时,$ [1,n] $ 中第 $ i $ 位上为 $ X $ 的个数为:$ (n//10^i + 1) * 10^{(i-1)} $
(b)当第 $ i $ 位的数字 $ <X $ 时,$ [1,n] $ 中第 $ i $ 位上为 $ X $ 的个数为:$ (n//10^i) * 10^{(i-1)} $
(c)当第 $ i $ 位的数字 $ =X $ 时,$ [1,n] $ 中第 $ i $ 位上为 $ X $ 的个数为:$ (n//10^i) * 10^{(i-1)} + (n 取模 10i-1*10+1) $
注意:$ // $ 表示整除的意思。
举例说明:
对于 $ [1,2593] $ 中 $ 5 $ 出现的次数:
(1)个位(从右至左第1位):由于个位 $ 3<5 $ ,故对照规律(b):$ 2593//10^1 \times 10^{(1-0)} = 259 $ ,也就是说,在 $ [0~2593] $ 中 $ 5 $ 在个位上出现了 $ 259 $ 次。
(2)十位(从右至左第2位):由于十位上的数字 $ 9>5 $ ,故对照规律(a): $ (2593//10^2+1) \times 10^{(2-1)}=260 $ ,也就是说,在 $ [0~2593] $ 中 $ 5 $ 在十位上出现了 $ 260 $ 次。
(3)百位(从右至左第3位):由于百位上的数字 $ 5=5 $ ,故对照规律(c): $ (2593//10^3) * 10^{(3-1)} + (2593取模103-5*10+1) = 294 $ ,也就是说,在 $ [0~2593] $ 中 $ 5 $ 在百位上出现了 $ 294 $ 次。
(4)千位(从右至左第4位):由于百千位上的数字 $ 2<5 $ ,故对照规律(b):$ (2593//10^4) \times 10^{(4-0)} = 0 $ ,也就是说,在 $ [0~2593] $ 中 $ 5 $ 在千位上出现了 $ 0 $ 次。
故 $ 5 $ 在 $ [1,2593] $ 中共出现了 $ 259+260+294+0=813 $ 次。
3 程序代码:
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
count = 0
tmp = n
i = 1
while tmp != 0:
# a为每位上的数字
a = tmp % 10
rem = n % (10**i)
con = n // (10**i)
base = 10**(i-1)
if a > 1:
count += (con + 1) * base
elif a < 1:
count += con * base
else:
count += con * base + (rem - 1*base + 1)
tmp = tmp // 10
i += 1
return count