剑指offer31

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

题目描述

题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?
为此他特别数了一下1~13中包含1的数字有110111213因此共出现6,
但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,
可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

解法一:基于位置的判断

/**************************************************************************************************************
注解:参考一位牛友提到的leetcode的链接网址(包括求1~n的所有整数中2,3,4,5,6,7,8,9出现的所有次数)
通过使用一个 位置乘子m 遍历数字的位置, m 分别为1,10,100,1000…etc.(m<=n)

对于每个位置来说,把10进制数分成两个部分,比如说 当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,…以此类推)。

再例如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)…以此类推)
**************************************************************************************************************************/
class Solution {
public:
    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;
    }
};

   转载规则


《剑指offer31》 赵小亮 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
剑指offer14 剑指offer14
剑指offer14:链表中倒数第K个结点 题目描述题目描述 输入一个链表,输出该链表中倒数第k个结点。 解法一:基于递归的方法class Solution { public: unsigned int cnt = 0; L
2020-05-11
下一篇 
剑指offer32 剑指offer32
剑指offer32:把数组排成最小的数 题目描述题目描述 输入一个正整数数组,把数组里所有数字拼接起来排成一个数, 打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321}, 则打印出这三个数字能排成的最小数字为321323。
2020-05-10
  目录