leetcode上看到了一个智商爆表的解法:
public int countDigitOne(int n) {
int ones = 0;
for (long m = 1; m <= n; m *= 10)
ones += (n/m + 8) / 10 * m + (n/m % 10 == 1 ? n%m + 1 : 0);
return ones;
}
现在使用a和b两个变量来解释该算法:
int countDigitOne(int n) {
int ones = 0;
for (long long m = 1; m <= n; m *= 10) {
int a = n/m, b = n%m;
ones += (a + 8) / 10 * m +( a % 10 == 1 ? (b + 1):0);
}
return ones;
}
通过m求从1到n中,每个十进制位出现1的次数,m取值1,10,100...为了求每个十进制位出现1的次数,我们把n分成两个部分,例如当用m=100来把n=3141592分成a=31415和b=92两个部分,求百位出现1的次数。此时把从1到3141592的数中,百位为1的数看做oooo1xx,其中oooo可以从0到3141,xx可以从0到99。因此百位的1出现3142*100次,也就是(a/10+1)*m。
再把m取1000判断千位上1出现的次数,同样的把n分成a=3141和b=592两个部分。把从1到3141592的数中,千位为1的数看做ooo1xxx,当ooo从0到313,xxx可以从0到999,当ooo是314的时候,xxx只可以从0到592了。因此千位的1出现313*1000+593次,也就是(a/10)*m+(b+1)。
因此我们可以知道当a的个位为2及以上时,次数是(a/10+1)*m。a的个位为1时,次数是(a/10)*m+(b+1)。a的个位为0时,次数是(a/10)*m。综上三种情况可以得到(a + 8) / 10 * m + (a % 10 == 1) ? (b + 1):0;
ps:原文地址:https://discuss.leetcode.com/topic/18054/4-lines-o-log-n-c-java-python
自己在翻译的基础上加入了自己的理解,并修改了一些用来描述的代码和表述
阅读(2638) | 评论(0) | 转发(0) |