算法 求数字1出现的次数

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

在leetcode看到的算法,非常非常nice,在这里记录一下:

public int countDigitOne(int n) {
    int ones = 0;
    for (long m = 1; m <= n; m *= 10)
        ones += (n/m + 8) / 10 * m + (n/m % 10 == 1 ? n%m + 1 : 0);
    return ones;
}

思路分析:

1.从最外层的for循环可以看出,每次遍历的m分别表示数字n的个位、十位、百位等,一直到n的最高位

2. 假设n = 41324 我们以m=100为例

   n/m = 413   ——-记作a

   n%m = 24   ——-记作b

现在就将 原来的 n 划分为 ab两个部分。

现在我们就可以考虑百位的1 重复出现的次数了:

     (1) 由于41324 原来的百位是 3 ,所以当 我们把百位数字置为1时,百位之前的数字共有 00—–42     即 a/10+1   (43)种可能

      (2)对于上面的43种情况,分别 有 00—–99 (个位和十位) 共 m(此时m为100)种可能

       (3)所以百位总共出现了 (a/10+1)*m

 3. 以m=1000重复上面的分析

    n/m = 41   ——–a

    n%m=324 ——–b

   这种情形由于千位数字原来 就是1 ,所以 千位之前只有 0–3 共4种可能 ,这四种可能每种都可以乘以 1000(m),此时共有  a/10* m 次。

  注意:当我们将千位之前的数字 置为最大 ,也就是万位取4, 千位之后只能 取 000—-324 ,共 b+1 次

 所以 千位的1出现了  a/10* m +(b+1) 次。

到这里可以看出 当 a%10 >= 2,a/10需要+1: 可以这样实现 (a +8)/10

还需要判断 a%10 == 1 时  加上  b+1

也就是上面的这段代码:n/m = a, n%m=b

(n/m + 8) / 10 * m + (n/m % 10 == 1 ? n%m + 1 : 0);

点赞