【leetcode】1~n中1的个数

描述:给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。

输入: 13
输出: 6 
解释: 数字 1 出现在以下数字中: 1, 10, 11, 12, 13 。

思路:假设找1235这个数

  • 先找个位上有几个1,按照规律,每10个数里个位就出现1个1,所以1235在个位上会出现1235/10 = 123个1;因为这里只计算了前1230个数,在1231~1235中的数的个位上还有1个1,所以个位上一共123+1= 124个1
  • 再看十位上,每100个数里十位就出现10个1,所以1235在十位上就出现1235/100*10 = 120个1,这里只计算了前1200个数,还有1201~1235这35个数的十位上有10个1,所以一共有120+10=130个1
  • 接着看百位上,每1000个数百位就出现100个1,所以1235在百位就出现1235/1000*100 = 100个1;这只计算了前1000个数,在1001~1235中百位上有1的个数为100个,所以一共100+100=200个1
  • 最后看千位上,每10000个数的千位中有1000个1,所以1235/10000*1000=0,这里1235没有满1000,前面的计算中没有1,但是1235在1000~1235这(235+1)个数中的千位都是1,所以都是一共有236个1
  • 因此一共124+130+200+236=690个1

根据上述的规律,可以将其分为两部分:

  • 前半部分:count1 = ( n // (num*10) ) * num , 在个位数上,num = 1;在十位上,num = 10 ……,这是前半部分的计算。
  • 后半部分:count2 = min(max(n % (num * 10) - num + 1, 0), num),先解释最外层,min函数用来控制求遗漏的1的个数,例如,在遗漏的个位上,最多只有一个1,因为个位只存在在0~9之间,再例如,在遗漏的百位上,最多只有10个1,即在0~99之间,在十位上只存在10~19这10个数,所以num位上最多num个1。再解释内层max函数,最少0个1,比如110,在个位上没有1;解释前一部分n % num - num + 1,拿110来说,要求其百位上的1,先求前半部分110/1000 * 100 = 0,现在就要看千位以1为首的还有多少党羽,这个时候要把就只能看千位后面的数,先n % (num * 10) 得到本身,然后减去num(这里的num就是减去100,因为要只剩除最高位后面的数),还要加1是因为漏掉了100这个数,110 % 1000 - 100 = 10,这里只是计算了101~110这10个数,忘记了100,所以再加上1。
    代码:
class Solution(object):
    def countDigitOne(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n <= 0:
            return 0
        count = 0
        num = 1
        while num <= n:
            count += ((n // (num * 10)) * num + min(max(n % (num*10) - num + 1,0),num))
            num *= 10
        return count

参考:https://leetcode-cn.com/problems/number-of-digit-one/solution/shu-zi-1-de-ge-shu-by-leetcode/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值