zoukankan      html  css  js  c++  java
  • [LeetCode] 233. Number of Digit One 数字1的个数

    Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

    For example:
    Given n = 13,
    Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.

    Hint:

    1. Beware of overflow.

    这道题让我们比给定数小的所有数中1出现的个数,之前有道类似的题 Number of 1 Bits,那道题是求转为二进数后1的个数,博主开始以为这道题也是要用那题的方法,其实不是的,这题实际上相当于一道找规律的题。那么为了找出规律,我们就先来列举下所有含1的数字,并每10个统计下个数,如下所示:

    1的个数          含1的数字                                                                        数字范围

    1                   1                                                                                     [1, 9]

    11                 111  111111119                              [10, 19]

    1                   21                                                                                   [20, 29]

    1                   31                                                                                   [30, 39]

    1                   41                                                                                   [40, 49]

    1                   51                                                                                   [50, 59]

    1                   61                                                                                   [60, 69]

    1                   71                                                                                   [70, 79]

    1                   8                                                                                  [80, 89]

    1                   91                                                                                   [90, 99]

    11                 100  101  102  103  104  105  106  107  108  109          [100, 109]

    21                 11111  11111111111111119             [110, 119]

    11                 120  121  122  123  124  125  126  127  128  129          [120, 129]

    ...                  ...                                                                                  ...

    通过上面的列举可以发现,100 以内的数字,除了10-19之间有 11 个 ‘1’ 之外,其余都只有1个。如果不考虑 [10, 19] 区间上那多出来的 10 个 ‘1’ 的话,那么在对任意一个两位数,十位数上的数字(加1)就代表1出现的个数,这时候再把多出的 10 个加上即可。比如 56 就有 (5+1)+10=16 个。如何知道是否要加上多出的 10 个呢,就要看十位上的数字是否大于等于2,是的话就要加上多余的 10 个 '1'。那么就可以用 (x+8)/10 来判断一个数是否大于等于2。对于三位数区间 [100, 199] 内的数也是一样,除了 [110, 119] 之间多出的10个数之外,共 21 个 ‘1’,其余的每 10 个数的区间都只有 11 个 ‘1’,所以 [100, 199] 内共有 21 + 11 * 9 = 120 个 ‘1’。那么现在想想 [0, 999] 区间内 ‘1’ 的个数怎么求?根据前面的结果,[0, 99] 内共有 20 个,[100, 199] 内共有 120 个,而其他每 100 个数内 ‘1’ 的个数也应该符合之前的规律,即也是 20 个,那么总共就有 120 + 20 * 9 = 300 个 ‘1’。那么还是可以用相同的方法来判断并累加1的个数,参见代码如下:

    解法一:

    class Solution {
    public:
        int countDigitOne(int n) {
            int res = 0, a = 1, b = 1;
            while (n > 0) {
                res += (n + 8) / 10 * a + (n % 10 == 1) * b;
                b += n % 10 * a;
                a *= 10;
                n /= 10;
            }
            return res;
        }
    };

    解法二:

    class Solution {
    public:
        int countDigitOne(int n) {
            int res = 0;
            for (long k = 1; k <= n; k *= 10) {
                long r = n / k, m = n % k;
                res += (r + 8) / 10 * k + (r % 10 == 1 ? m + 1 : 0);
            }
            return res;
        }
    };

    Github 同步地址:

    https://github.com/grandyang/leetcode/issues/233

    类似题目:

    Factorial Trailing Zeroes

    Digit Count in Range

    参考资料:

    https://leetcode.com/problems/number-of-digit-one/

    https://leetcode.com/problems/number-of-digit-one/discuss/64390/AC-short-Java-solution

    https://leetcode.com/problems/number-of-digit-one/discuss/64381/4+-lines-O(log-n)-C++JavaPython

    LeetCode All in One 题目讲解汇总(持续更新中...)

  • 相关阅读:
    TCP/IP协议栈与数据包封装+TCP与UDP区别
    MySQL数据库优化总结
    MySQL存储引擎,锁,优化简述
    java实现常见查找算法
    Java的几种常见排序算法
    UML类图学习
    高性能的RTC服务器OpenFire
    常用的设计模式
    Swing JInternalFrame的使用
    Qt 模态与非模态
  • 原文地址:https://www.cnblogs.com/grandyang/p/4629032.html
Copyright © 2011-2022 走看看