• 【LeetCode】233. 数字 1 的个数


    题目

    给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。

    示例:

    输入: 13
    输出: 6 
    解释: 数字 1 出现在以下数字中: 1, 10, 11, 12, 13 。
    

    本题同【剑指Offer】面试题43. 1~n整数中1出现的次数

    思路

    通过一个例子来找到规律,比如数字21345,我们把1-21345分为两部分,一段是1-1345,另一段是1346-21345。

    • 对于1346-21345中1出现次数,分为两种情况:
      (1)1出现在最高为(本例为万位),即10000-19999这10000(10^4)个数字万位中。然而,并不是对所有的5位数万位出现的次数都是10000次,如12345,1只出现在10000-12345的万位,出现次数为2346次,即除去最高位之后剩下的数再加上1(2345+1)
      (2)1出现在除最高位之外的其它4位数中,可能有四种情况,对于每种情况,其它3个位置可以任选0-9这10个数,由于最高位是2,可以把1346-21345再分为两段:1346-11345和11346-21345,每段后四位数中,1出现次数为4 * 10^3 = 4000,所以总共为2 * 4000 = 8000。
    • 对于1-1345中1出现次数,可以利用递归计算出。

    本题中为了便于计算数字位数,将其转为字符串。

    代码

    时间复杂度:O(logn),递归次数和位数相同,一个数字n有O(logn)位。
    空间复杂度:O(1)

    class Solution {
    public:
        int countDigitOne(int n) {
            string str = to_string(n);
            return helper(str);
        }
    
        int helper(string str) {
            if (str.empty()) return 0;
            int len = str.size();
            int first = str[0] - '0';
            if (len == 1 && first == 0) return 0;
            if (len == 1 && first > 0) return 1;
            int numFirst = 0;
            if (first > 1) numFirst = pow(10, len - 1);
            else if (first == 1) numFirst = stoi(str.substr(1)) + 1;
            int numOther = first * (len - 1) * pow(10, len - 2);
            int numRec = helper(str.substr(1));      
            return numFirst + numOther + numRec;
        }
    };
    

    另一种写法

    时间复杂度:O(logn)
    空间复杂度:O(1)

    class Solution {
    public:
        int countDigitOne(int n) {
            if (n < 1) {
                return 0;
            }
            int len = getLen(n);
            if (len == 1) {
                return 1;
            }
            int tmp = pow(10, len-1);
            int first = n / tmp;
            int firstOne = first == 1 ? n % tmp + 1 : tmp;
            int otherOne = first * (len - 1) * (tmp / 10);
            return firstOne + otherOne + countDigitOne(n%tmp);
        }
        int getLen(int n) {
            int c = 0;
            while (n) {
                ++c;
                n /= 10;
            }
            return c;
        }
    };
    
  • 相关阅读:
    MySQL SQL语言学习
    02-MySQL执行计划详解(EXPLAIN)
    linux下删除oracle11g单实例的方法
    01. Oracle 实例恢复
    替代变量与SQL*Plus环境设置
    9. Oracle 归档日志
    8. Oracle 联机重做日志文件(ONLINE LOG FILE)
    7. Oracle 控制文件(CONTROLFILE)
    6. Oracle 回滚(ROLLBACK)和撤销(UNDO)
    5. Oracle 表空间与数据文件
  • 原文地址:https://www.cnblogs.com/galaxy-hao/p/12897559.html
Copyright © 2020-2023  润新知