题目:
输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:输入:n = 12 输出:5
示例 2:输入:n = 13 输出:6
限制:1 <= n < 2^31
解题思路:
首先可以通过枚举找规律:0~9只有一个1,10~99十位上有10个1,100~999百位上有100个1...以此类推。可以得出结论:
- 0~9:只有一个1,那么如果某数是10的a倍,那么个位上就有a个1;
- 10~99:十位上有10个1,即10~19,那么如果某数是100的a倍,是10的b倍,那么十位有a*10个1,个位有b个1,共(a*10+b)个1;
- 100~999:百位上有100个,即100~199,那么如果某数是1000的a倍,100的b倍,是10的c倍,那么百位有a*100个1,十位有b*10个1,个位有c个1,共(a*100,b*10+c)个1;
- ...
余数规则:
如果某数是100的x倍,根据余数y判断实际十位共有几个1:
- y>=20: (x+1)*10
- 10<=y<20: y+1+(x-1)*10
- y<10: x*10
比如:n=2012,那么1~2012共有几个1,
- a = 1, b = 10, 根据x, y = divmod(n, b)可知,x = 201, y = 2, 因为2 >= 2 * a,那么个位共有 201 + 1个1, one_count = 202
- a = 10, b = 100, 此时x = 20, y = 12, 因为 a <= 12 < 2 * a,那么十位共有 (12 + 1 + (20 -1) * 10)个1, one_count = 202 + 203 = 405
- a = 100, b = 1000, 此时x = 2, y = 12, 因为 12 < a,那么百位共有 (2 * 100)个1, one_count = 405 + 200 = 605
- a = 1000, b = 100000, 此时x = 0, y = 2012, 因为 2012 >= 2 * a,那么千位共有1000个1, one_count = 605 + 1000 = 1605
代码:
class Solution:
def countDigitOne(self, n: int) -> int:
a, b, one_count = 1, 10, 0
while n >= a:
x, y = divmod(n, b)
if y >= a * 2:
one_count += (x + 1) * a
elif y >= a:
one_count += y + 1 + (x - 1) * a
else:
one_count += x * a
a, b = b, b*10
return one_count
参考链接:https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/ji-jian-jie-fa-by-harrisliao/