Leetcode 刷题 - 233 - Number of Digit One

Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.


根据题意,计算在数字N之前出现过几次1.


用概率统计来计算,假设从个位开始,每次假设一个进位是1,然后统计剩下位数的数字变化的可能性。

class Solution(object):
    def countDigitOne(self, n):

        multipler = 1 # 记录位数的移动
        count = 0 # 记录1的数量
        while multipler <= n:
            quotient = n / (multipler * 10) # 得到某一个位数置1后的商
            remainder = n % multipler # 得到某一位数置1后的余数
            current = (n / multipler) % 10 # 置1位置的当前数值

            if current == 0:
                count += quotient * multipler
            if current == 1: # 这步下面有更新
                if not quotient:
                    count += remainder + 1
                else:
                    count += (quotient * multipler + remainder) + 1 
            if current > 1:
                count += (quotient + 1) * multipler

            multipler *= 10

        return count


用数字来举例:

@1. 392 -> 180

39x,把个位作为1,那么就有(00~39)种可能性,计40.

3x2,把十位作为1,这里不是(00~32),因为十位大于1,所以个位0~9都可以,依旧是(00~39)中可能性,计40.

x92,把百位作为1,同样因为百位大于1,所以就有(00~99)种可能性,计100.

一共40 + 40 + 100 -> 180

====

大于1的时候

if current > 1:
    count += (quotient + 1) * multipler

====


@2. 如果最后一位刚好是1的话

1392 -> 873

同上,139x,有(000~139),计140.

13x2,有(000~139),计140.

1x92,有(000~199),计200.

x392,千位是1,所以不是(000~999),而是只有(000~392)种可能性,计393.

一共140 + 140 + 200 + 393 -> 873

====

首位是1的时候

if not quotient:
    count += remainder + 1

只是加上剩余的数

====


@3. 如果之前的位刚好是1的话

111 -> 36

11x,有(00~11),计12. (理由同@1)

1x1,有(00~11),计12. (因为十位是1,所以只有(00~11),之后的(12~19)并不在内,否则就超过了数字最大值。)

x11,有(00~11),计12. (理由同@2)

一共12 + 12 + 12 -> 36

====

如果,非首位是1的话

else:
    count += (quotient * multipler + remainder) + 1

因为不能超过数字的最大值,所以非置1位之外的数字的所有可能性。可以和@1,@4比较下

====

if current == 1:
    count += (quotient * multipler + remainder) + 1

当前位置是1的时候,可以缩成一句,因为首位是1的话,quotient是0,刚好是remainder+1


@4. 如果之前的位刚好是0的话

102 -> 24

10x,有(00~10),计11. (理由同@1)

1x2,因为刚好是0,所以有(00~09),计10. (因为刚好十位是0,所以(10~19)不可以,生成的数字会超过最大值)

x02,有(00~02),计3. (理由同@2)

一共 11 + 10 + 3 -> 24

====

刚好是0的话

if current == 0:
    count += quotient * multipler

同样的边界条件,不超过数字的最大值,所以只能是上一位的整数值。

====



=======================

class Solution(object):
    def countDigitOne(self, n):
        ones, m = 0, 1
        while m <= n:
            ones += (n/m + 8) / 10 * m + (n/m % 10 == 1) * (n%m + 1)
            m *= 10
        return ones

很明显的关键在这句

(n/m + 8) / 10 * m + (n/m % 10 == 1) * (n%m + 1)

简单来说,就是第一个方法的缩写。依旧是根据当前位置的数字做判断,有三种需要判断,0,1,>=2.

当0的时候,n/m得到的值,最后一个肯定是0,加上了8,就是abc8这样的数字。然后n/m%10就是0,刚好除尽。所以当时0的时候,就单纯的等于

quotient * multipler
商 * 位


当1的时候,n/m得到的值,最后一个肯定是1,加上了9,就是abc9这样的数字,依旧不变。然后n/m%10就是1,刚好是1。所以当时0的时候,就单纯的等于

quotient * multipler + remainder + 1
商 * 位 + 余数 + 1.   (其实不用判断首位是不是1得可能性,因为首位是1的时候,会得到(1+8)/10*m,9/10 是0)。


当大于1的时候,(n/m+8)/10肯定进位,n/m%10肯定不等于1。所以就等于

(quotient + 1) * multipler

(商+1)* 位



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值