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.
算法一,递归
1. 初始条件为,0~9时,1的个数为1
2. 当给定一整数,首先找到它的最高位的数字,同时求出其权重。
例如 4139, 最高位的数字为 4, 权重为 1000。 即4的每个单位代表 1000
3. 用递归的方式求出小于权重所有数中出现1出现的个数。如上例,countDigitOne(1000-1)。 其结果,记为count
4. 现在,小于等于4139中1出现的个数,一定包含 4 * count
即0XXX, 1XXX, 2XXX, 3XXX 我们通过步骤3求出了XXX中所能出现的1的个数。 X表示0~9
5. 特例是, 1XXX 还需要考虑最高位这个1,所出现的次数。
如果最高位>1,则1XXX中最高位1出现的个数为 权重, 此例中为 1000
如果最高位为1, 则是余数+1. 此例中 是 139 +1, 表示 1000 ~ 1139。 共 140个数
6. 最后再用递方式,求出余数中1出现的个数。
即countDigitOne(139)
总结为,计算 4139的话,
先求出4000以内1的个数, 即 0~999, 1000~1999, 2000~2999, 3000~3999 。 4 倍于 0~999
再求1XXX中最高位所带来的1的个数, 即1000~1999
最后求零头139内中1的个数,即0~139
计算 139时
先求 100以内1的个数, 即0~99, 1倍于0~99
再求1XX中最高位1所带来的个数,100~139, 共 40个。 注,上面用的是权重,此用的是余数+1.
最后求零头 39内1的个数。 即 0~39
class Solution {
public:
int countDigitOne(int n) {
if (n <= 0)
return 0;
if (n <= 9)
return 1;
int m = 1;
int msd = n; // most significant digit
while (msd > 9) {
msd /= 10;
m *= 10;
}
int count = countDigitOne(m-1);
int total = 0;
total += msd * count;
if (msd > 1) {
total += m;
}
else if (msd == 1)
total += n % m + 1; // remainder
total += countDigitOne(n % m);
return total;
}
};
算法二,统计每个位置上1出现的个数。
我们知道,十进制整数有个位,十位,百位,千位,万位。。。
在每个位置上,取值范围0~9.
算法思路为,统计当一个位置取值为1时,在给定的范围内共有多少个可能的数字。
然后就是将所有这些统计值累加起来。即个位上为1的 + 百位上为1的 。。。。
1. 例如,给定范围为31415, 统计百位上为1时,共能有多少个数字。
即满足AA1XX这种模式,同时值小于等31415. A,X都代表0~9
一共有多少个呢
此时,AA的可能取值范围为 00~ 31, XX为 00~99.
故,共有 32 * 100 个数满足条件。
2. 此处有一个边界条件需要考虑。比如当数字为31115,即百位上的数字,等于1时。
AA1XX AA取值范围为 0~30, 不再是 0~31. 因为当AA取值31时,XX是不能取值0~99, 只能是 0~15
故要分成2部分来计算
第一部分同上,为 31 * 100 个数 , 即 AA 取值 0~30, XX 取值 0~99. 相对例子1来说,AA取值少了一个。
第二部分,当AA取值 31, XX取值0~15, 共有 16个数。
3. 第三个特例是,百位数上为0时,就不需要第二部分的计算。
比如 31015, 满足AA1XX的数, 只能是AA 0~30, XX 0~99 一种情况。 相对于例子1来说,AA取值少了一个。
即一个位置上的数,分成3种情况。即
0, 1, 2~9
在下面程序中,0 和 2~9。 是两种情况一起处理的。 即通过 + 8 )/ 10这种运算.
(n/m + 8) / 10 * m
同时,在额外处理为1的情况。
(n / m % 10 == 1 ? n % m + 1 : 0)
class Solution {
public:
int countDigitOne(int n) {
int count = 0;
for (long long m=1; m<=n; m*=10) {
count += (n/m + 8) / 10 * m + (n / m % 10 == 1 ? n % m + 1 : 0);
}
return count;
}
};
算法来源:
https://leetcode.com/discuss/44281/4-lines-o-log-n-c-java-python