输入一个整数 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 1~n 1~n 这 n n n 个整数中,第 i i i 位上出现 1 1 1 的次数,即当第 i i i 位取值为 1 1 1 时,求解存在多少个 < n <n <n 的不同整数。则,依次对个位、十位、百位… 求解并相加即可得到总次数。
最直观的写法如下:
class Solution:
def countDigitOne(self, n: int) -> int:
digits = str(n)
N,count = len(digits),0
# 遍历每一位数字,计算当idx位取值为1时,整数的个数
for idx,d in enumerate(digits):
# 当高位部分数字小于N的高位部分时,低位任意取值,构成的数字均比N小
# idx == 0 表示当前位已经是最高位,故不存在该情况
if idx > 0: count += int(digits[:idx]) * pow(10,N - idx - 1)
# 考虑高位部分数字与N的取值相同的情况
# 若当前位==0,则不存在取值为1的情况
# 若当前位==1,则低位最大取值与N相同
# 若当前位 >1,则低位任意取值
if idx == N - 1: count += 1 if d != '0' else 0
elif d != '0': count += int(digits[idx + 1:]) + 1 if d == "1" else pow(10,N - idx - 1)
return count
进一步优化高位和低位数字的求解过程:
class Solution:
def countDigitOne(self, n: int) -> int:
high,low,cur = n,0,0
count,pos = 0,1
while high > 0:
high, cur = high // 10, high % 10
count += high * pos
if cur > 0: count += low + 1 if cur == 1 else pos
low, pos = low + cur * pos, pos * 10
return count