输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
暴力的方法是将每一个数都依次判断每一位上是否是1,然后相加,这样无法通过,时间超过限制。
可以考虑计算每一位可能出现1的总次数,然后把每一位相加。时间复杂度是nlgn。
其实是把每一位分开进行的计算。
下面的方法时间复杂度是lgn,一个while循环,n / (10**T) = 1, T = logn
其中遇到的问题:
- 乘方是**,而不是^, 这是异或的意思
- 5/2 = 2.5 , 5//2 = 2
- 是计算每一位上可能出现1的次数,只需要计算该位的,并且不会发生重叠,因为每次都只计算自己,题意是要计算各个位上所有的1的次数,而不是出现1的数字的次数之和。
- 下面的代码按大于1,小于1,和等于1来展开,三种情况,对应的某一位为1的次数是不同的。值得注意的是,如果该位是1,那么可以举例:21343,倒数第四位是1,此时,跟22343的区别是,22343多了21344-21999的次数,所以直接加上343+1(注意可以为0),为10 ** 3 * 2+343+1。如果是22343那么是10 ** 3 * 3。小于1的话,如20343,那么是10 ** 3 * 2,对比相等少去了后面的部分。
class Solution(object):
def countDigitOne(self, n):
# 分为大于1,小于1,等于1三种情况,分别计数每一位上的1可能出现的总数,再相加。
if n < 0:
return
def countone(n,x): # 倒数第x位
cur = n // (10**(x-1)) # 该位的数值
one = cur % 10
prenum = n // (10**x) # 前面的整数部分
postnum = n % (10**(x-1)) # 后面的整数部分
if one > 1:
count = 10**(x-1)*(prenum+1) # 拆开比较麻烦,因为后面是9/99/999...
elif one == 1 :
count = 10**(x-1)*(prenum) + postnum + 1
else:
count = 10**(x-1)*(prenum) # 也可以是 (prenum-1) * 10**(x-1) + postnum + 1
return count
copyn = n
count = 0
x = 1
while copyn > 0:
copyn = copyn // 10
count += countone(n,x)
x += 1
return count