【转载】剑指 Offer 43. 1~n整数中1出现的次数

题目链接

题解来自

本题主要是找规律。暴力算法会超时。
我们先来看一个简单的规律:
设f(n)是只从0到n位数的最大值一共有多少个1,
f(1) = 计算0~9有多少个1 = 1;
f(2) = 计算0~99有多少个1;

我们先把1开头的十位数单独拿出来考虑且只考虑十位数上1的个数:10~19共有10个1;
然后再考虑个位数上1的个数,此时十位数范围从0~9,每种十位数对应1个个数均为f(1);
综合得f(2) = 10 + 10 * f(1) = 20;
同理 f(3) = 计算0~999有多少个1

先把1开头的百位数单独拿出来考虑,且只考虑百位数:100~199,共100个1;
再考虑其他位数上1的个数,此时百位数范围从0~9,每种百位数对应1个数均为f(2);
综合得 f(3) = 100 + 10 * f(2) = 300;
针对题目中数字最大为2^31次方,最多只有10位数。所以综上所述我们可以列出f(n)
f(1) = 1;
f(2) = 20;
f(3) = 300;
f(4) = 4000;
f(5) = 50000;
f(6) = 600000;
f(7) = 7000000;
f(8) = 80000000;
f(9) = 900000000;
f(10) = ‭10,000,000,000‬;

针对随便一个数如2345,如何计算其包含的1的个数。
同理规律中的计算:

首先考虑千位数 即0345~2345共多少个1
只考虑千位数:1000~1999:共1000个
除了千位数后续其他位数:2 * f(3) = 600个
考虑百位数及其后续位数 即0045~0345 共有多少个1
只考虑百位数:100~199 :100个
除了百位后续其他位:3 * f(2) = 60个
考虑十位及其后续位数,即0005~0045共有多少个1
只考虑十位:10~19:共 10个
十位后的其他位:4 * f(1) = 4个
最后考虑个位:0000~0005共有多少个1
如果个位不为0,则有1个
如果个位为0 则有0个
共1600 + 160 + 14 + 1 = 1775
好,有了上述步骤后,因为上述步骤没有出现某一位<=1 ,我们还需考虑如果某一位<=1是怎样的情况,
如1045:
在考虑千位数时,只考虑千位数的结果就不是1000了,而是1000~1045,共46个
同时在考虑百位数值,只考虑百位数的结果就不是100了,而是000~000,共0个

首先考虑千位数 即0045~1045共多少个1
只考虑千位数:1000~1045:共46个
除了千位数后续其他位数:1 * f(3) = 300个
考虑百位数及其后续位数 即0045~0045 共有多少个1
只考虑百位数:000~000 :0个
除了百位后续其他位:0 * f(2) = 0个
考虑十位及其后续位数,即0005~0045共有多少个1
只考虑十位:10~19:共 10个
十位后的其他位:4 * f(1) = 4个
最后考虑个位:0000~0005共有多少个1
*如果个位不为0,则有1个
*如果个位为0 则有0个
共:346 + 0 + 14 + 1 = 361个

作者:indere-3
链接:https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/zhao-gui-lu-jie-fa-shuang-100-by-indere-3/
来源:力扣(LeetCode)

int countDigitOne(int n){
	int record[] = {0, 1, 20, 300, 4000, 50000, 600000, 7000000, 80000000, 900000000};
    int count = 0;
    int res = 0;
    long flag = 1;
    int tmp = n;
    while(tmp != 0){
       int num = tmp % 10;
       tmp /= 10;
       res = res + record[count] * num;
       if(num > 1){
           res += flag;
       }else if(num == 1){
           res += n % flag + 1;
       }
       count++;
       flag *= 10;
    }
    return res;
}
posted @ 2020-09-26 14:26  Bears9  阅读(119)  评论(0编辑  收藏  举报