题解 | #整数中1出现的次数(从1到n整数中1出现的次数)#

整数中1出现的次数(从1到n整数中1出现的次数)

http://www.nowcoder.com/practice/bd7f978302044eee894445e244c7eee6

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n) {
        if (n <= 0) {
            return 0;
        }
        string str = to_string(n);             
        return numberOf1(str);
    }


    int numberOf1(string str){
        int length = str.size();      
        if (length == 1) {
            return  str[0] == '0' ? 0 : 1;
        }

        // 21345为例,把他分为了1~1345和1346~21345 numFirstDigit和numOtherDigits用于统计1346~21345的1中的个数 
        // numRecursive 用于统计1~1345的个数,这样分是为了好迭代,轮询次数就是N的位数,也就是logN  + 1,复杂度就是O(logN),其中log以10为底

        //  首位为1的数有多少 1就出现了多少次(只考虑首位的1,其他位数的1不考虑 只考虑首位为最高位 比如21345 只考虑10000~21345 首位为万位 不考虑1345这种首位为千位)
        int numFirstDigit = 0;
        if(str[0] > '1') {
            //  当首位大于1时,首位为1的数即10000~19999的所有数  20000~21345首位不是1(2x...x 3x..x中首位为1的数为0)
            numFirstDigit = pow(10, length - 1);  
        }
        else if (str[0] == '1') {
            //  当首位大于1时,首位为1的数即10..0~1x..x的所有数 即(x..x - 0..0) + 1 即 x..x + 1 上一个判断也可以这么算 9999 + 1 就是10^4 
            numFirstDigit = stoi(str.substr(1)) + 1;
        }
        //  统计其他位为1的个数,再将数分为1346~11345和11346~21345 然后算后4位出现1的次数。每一段后4位其实都是0000~9999的组合
        //  以选择其中1位为1,其他位在0~9这10个数中任意选,就是10^length(其他位) 每一位都可以被选择一次 就是length*10^(length - 1)
        //    ps 统计不是排列组合的种数,是1的次数,以1211为例,选第一位为1时,1211计了一个1,选第三位为1时,也会排列出1211,但是这也只计了一个1,所以对统计1的个数来说,没有重复
        int numOtherDigits = (length - 1) * pow(10, length - 2);       
        //  如果N=31345 就要分为3段,1346~11345、11346~21345、21346~31345 所以要乘以分的段数 即首位的值
        numOtherDigits *= (str[0] - '0');   //  这里拆成两步好解释理解 实际可以写成一步 int numOtherDigits = (str[0] - '0') * (length - 1) * pow(10, length - 2);
        int numRecursive = numberOf1(str.substr(1));  

        return numFirstDigit + numOtherDigits + numRecursive;
    }
};
全部评论

相关推荐

喜欢走神的孤勇者练习时长两年半:池是池,发是发,我曾池,我现黑
点赞 评论 收藏
分享
杨柳哥:这不是普通人,那这个钱的是天才
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务