《剑指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

posted @ 2018-06-20 20:19  EEEEEcho  阅读(258)  评论(0编辑  收藏  举报