JZ31 整数中1出现的次数(从1到n整数中1出现的次数)

描述

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数
例如,1~13中包含1的数字有1、10、11、12、13因此共出现6次

好多题解都看不懂呀,暴力解法肯定不太行,有可能n太大。

先来看看讨论组的数学归纳法:https://blog.nowcoder.net/n/562472a7292842dbb320d827b1a94031?f=comment

另外讨论组提供的Python代码:(困扰,看会视频再来)

# -*- coding:utf-8 -*-
class Solution:
    def countDigitOne(self, n):
        """
        :type n: int
        :rtype: int

        例:对于824883294,先求0-800000000之间(不包括800000000)的,再求0-24883294之间的。
        如果等于1,如1244444,先求0-1000000之间,再求1000000-1244444,
        那么只需要加上244444+1,再求0-244444之间的1
        如果大于1,例:0-800000000之间1的个数为8个100000000的1的个数加上100000000,
        因为从1000000000-200000000共有1000000000个数且最高位都为1。
        对于最后一位数,如果大于1,直接加上1即可。
        """
        result = 0
        if n < 0:
            return 0
        length = len(str(n))
        listN = list(str(n))
        for i, v in enumerate(listN):
            a = length - i - 1  # a为10的幂
            if i==length-1 and int(v)>=1:
                result+=1
                break

            if int(v) > 1:
                result += int(10 ** a * a / 10) * int(v) + 10**a
            if int(v) == 1:
                result += (int(10 ** a * a / 10) + int("".join(listN[i+1:])) + 1)
        return result

姚青林老师的视频讲解:https://www.bilibili.com/video/BV1K4411o7KP?p=28

假设要算1~3459082190:

 ①假如对于0这一位,它这时是0,如果要让它变成1呢?(0的情况)

先看前面部分,让0这一位往前面借1,所以前面只有3458,前面这四个数可以从0变化到3458(有3459变化次数),因为如果借了1,此时就算前面是3458,那么34581也是比34590要小的。

这时候看后面,因为此时0这一位变成1,所以后面每一位数都可以从0变化到9,所以总次数为10^5,所以综上所述,除了0这一位的变化,其他位的变化总次数为3459*10^5

②假如对于8这一位,它这时是8,那么要让他变成1呢?(比1大的情况)

因为这一位是8,所以不需要向前面借位,所以前面的34590可以从0到34590(有34591变化次数),因为34591也比34598小。

这时候加上后面的变化次数,所以其他位的变化总次数为34591*10^4.

③假如对于1这一位,它这时等于1怎么办呢?(本身为1的情况)

前面部分依旧是从0变化到3459082(有3459083变化次数),那这个时候后面呢?

因为如果这个数本身就是1,等于说不能超过后面数字的区间,因为如果是······191就超出了我们这个n的数。

所以后面的变化次数为90,即其他位的变化总次数为3459083*91

但是后面要是90以后的91,92,93···

这个时候等于说1这一位的1是需要往前面借一位得到的,所以就是前面的变化次数乘后面的变化次数3459082*9

综上所述,其他位的变化总次数为3459083*90+3459082*9

所以按照这三种情况,把所有位数的for循环写出来!

class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        if n == 1:
            return n
        #循环的出口
        precise = 1
        highValue = 1
        midValue = 1
        lowValue = 1
        count = 0
        sumNum = 0
        while highValue != 0:
            highValue = n//(precise*10)
            midValue = (n//precise)%10
            lowValue = n % precise
            precise = precise*10
            if midValue == 0:
                num = (highValue -1 +1)*pow(10,count)
                sumNum += num
            elif midValue > 1:
                num = (highValue+1)*pow(10,count)
            else:
                num = highValue*pow(10,count) + lowValue
            sumNum += num
            count += 1
        return sumNum
a = Solution()
m1 = a.NumberOf1Between1AndN_Solution(13)
print('m1=', m1)

姚老师的代码在n=1的时候不能通过,所以我就加了第一句判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值