输入一个整数 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
解题思路
总体思想就是分类,先求所有数中个位是 1 的个数,再求十位是 1 的个数,再求百位是 1 的个数…
假设 n = xyzdabc,此时我们求千位是 1 的个数,也就是 d 所在的位置。
那么此时有三种情况,
d == 0,那么千位上 1 的个数就是 xyz * 1000
d == 1,那么千位上 1 的个数就是 xyz * 1000 + abc + 1
d > 1,那么千位上 1 的个数就是 xyz * 1000 + 1000
为什么呢?
当我们考虑千位是 1 的时候,我们将千位定为 1,也就是 xyz1abc。
对于 xyz 的话,可以取 0,1,2…(xyz-1),也就是 xyz 种可能。
当 xyz 固定为上边其中的一个数的时候,abc 可以取 0,1,2…999,也就是 1000 种可能。
这样的话,总共就是 xyz*1000 种可能。
注意到,我们前三位只取到了 xyz-1,那么如果取 xyz 呢?
此时就出现了上边的三种情况,取决于 d 的值。
d == 1 的时候,千位刚好是 1,此时 abc 可以取的值就是 0 到 abc ,所以多加了 abc + 1。
d > 1 的时候,d 如果取 1,那么 abc 就可以取 0 到 999,此时就多加了 1000。
class Solution:
def countDigitOne(self, n: int) -> int:
# cur表示当前位
cur = n % 10
# high为当前位前面的高位,比如数xyzabc,当前位为a,则高位为xyz,低位为bc
high = n // 10
# low为当前为位后面的低位
low = 0
# digital表示位数,个位为1,十位为10,一次类推
digital = 1
# res为总的结果
res = 0
while high!=0 or cur!=0:
# 如果当前位为0,则只与高位相关
if cur==0:
res += high * digital
# 如果当前位为1
elif cur==1:
res += high * digital + low + 1
#
else:
res += high * digital + digital
low += cur * digital
cur = high % 10
high //= 10
digital *= 10
return res