(C++)剑指offer-31:整数中1出现的次数(时间效率)

剑指offer-31:整数中1出现的次数(从1到n整数中1出现的次数)

目录

1题目描述

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。

ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
这里写图片描述

2题目解析及答案

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n){ 
        int ones = 0;
        for (long long m = 1; m <= n; m *= 10)
            ones += (n/m + 8) / 10 * m + (n/m % 10 == 1) * (n%m + 1);
         return ones;
    }
};
  • int a = n/m, b = n%m;
  • 注解:参考leetcode(包括求1~n的所有整数中2,3,4,5,6,7,8,9出现的所有次数)
  • 通过使用一个位置乘子m 遍历数字的位置, m 分别为1,10,100,1000…etc.(m<=n)

对于每个位置来说,把10进制数分成两个部分

(1)比如说当m=100的时候, 把十进制数 n=3141592 分成 a=31415 和 b=92 ,以此来分析百位数为1时所有数的个数和。

m=100时,百位数的前缀为3141
当百位数大于1时,为3142*100,因为当百位数大于1时,前缀可以为0,即百位数可以从100到199,共100个数;
当百位数不大于1时,为3141*100;

如何判断百位数是否大于1?

假设百位数为x,若(x+8)/10等于1,则大于1,若(x+8)/10等于0,则小于1。
因此前缀可用(n/m + 8)/10 *m来计算(若计算2的个数,可以改为(n/m + 7)/10*m,若计算3的个数,改为(n/m + 6)/10*m,…以此类推)。

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

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

即(n/m%10==1)判断第m位是否为1,若为1,则加上(b+1),若不为1,则只计算前缀。

(若计算2的个数,可以改为(n/m%10==2)(b+1),若计算3的个数,可以改为(n/m%10==3)(b+1)…以此类推)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值