统计从1到n中1出现的次数?

Leetcode NUM1
统计从1到n中1出现的次数?

解题思路一(代码简单思路较难想到):

通过使用一个位置乘子m 遍历数字的位置, m 分别为1,10,100,1000…etc.(m<=n)
对于每个位置来说,把10进制数分成两个部分,比如说 当m=100的时候, 把十进制数 n=3141592 分成 a=31415 和 b=92 ,以此来分析百位数为1时所有数的个数和。m=100时,百位数的前缀为3141,当百位数大于1时,为3142100,因为当百位数大于1时,前缀可以为0,即百位数可以从100到199,共100个数;当百位数不大于1时,为3141100;如何判断百位数是否大于1?假设百位数为x,若(x+8)/10等于1,则大于1,若(x+8)/10等于0,则小于1。因此前缀可用(n/m + 8)/10 m来计算(若计算2的个数,可以改为(n/m + 7)/10m,若计算3的个数,改为(n/m + 6)/10*m,…以此类推)。

再例如m=1000时,n分为a=3141和 b=592;千位数的前缀为314,千位数不大于1,故前缀计算为3141000;因为千位数为1,再加b+1(0到592)。即千位数为1的所有书的个数和为3141000+592+1;公式(n/m + 8)/10*m + b +1。

注意:只有n的第m位为1时需要计算后缀,后缀计算为 (n/m%10==1)*(b+1),

即(n/m%101)判断第m位是否为1,若为1,则加上(b+1),若不为1,则只计算前缀。(若计算2的个数,可以改为(n/m%102)(b+1),若计算3的个数,可以改为(n/m%10==3)(b+1)…以此类推)
代码:

int NumberOf1Between1AndN_Solution(int n)
    {
        int cnt = 0;
        int a=0,b=0;
        for(long long m=1;m<=n;m*=10){
            a = n/m;
            b = n%m;
            cnt+=(a+8)/10*m + (a%10==1)*(b+1);
        }
        return cnt;
    }

解题思路2:

出现1无非是在个位、十位、百位、千位。。。等出现,那对一个数判断是否有1便是判断他的各个位有没有1出现。

例子:
(1)个位上出现1的数有什么规律呢,个位出现1的数可写作x10+1, 则有 ((x10+1)-1)%10<1.
(2)十位上出现1的数又有什么规律呢,十位出现1的数可写作 x100+10+y,(y<10),则有 ((x100+10+y)-10)%100=y<10.
(3)再来,百位出现1的数字有什么规律呢,百位出现1的数可写作x1000+100+y,y<100,则有((x1000+100+y)-100)%1000=y<100
总结:举例子只是为了方便理解,统一的来说,当10的k次方出现的1的数都可以写作,number=x*10(k+1)+10k+y,其中y<10k,则恒有(number-10k)%10(k+1)<=y<10k
方法:对一个数是否满足条件来说,先求出该数的位数length,然后遍历k=1->length,判断是否有满足上式的k值存在,若存在,则该数符合条件。
代码:

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        int res = 0, length;
        for (int i = 1; i <= n; i++) {
            length = 0;
            while (i >= pow(10, length)) {
                if (((i -(int) pow(10, length)) % (int)pow(10, length + 1))<pow(10, length))
                    res++;
                length++;
           }
        }
        return res;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jancy、

知识付费,支持一下~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值