本文中的code和思想来自于https://leetcode.com/discuss/44281/4-lines-o-log-n-c-java-python ,感谢作者
code如下:
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);
}
return ones;
}
m为从1开始到N之间的所有的10的倍数值。比如1 , 10 ,100 ...
通过m可以将n划分成为两个部分,比如数字3141592 , 那么当m = 100的时候,划分的结果是31415 和 92 ,那么百位的前缀就是从“ ”到“3141” ,这个看成是3142条的数据,因为这个是百位的前缀。那么百位是1的元素就有,(a/10 + 1)*100个
然后来看看千位,同时千位就是m = 1000 的时候,这个时候可以将数字划分为 a = 3141 和 b = 592 ,千位的前缀就是 从“ ” 到“314” ,一共有315次,然而, 因为千位是1,最后一条只有593 条的数据,也就是 从”000“到”592“ ,所以要分开算。那么加起来,这个情况一共有( a/10 *1000 ) + (b +1 ) 次
然后比较魔幻的是,上面两种情况
当a/10 最后一为是 0 ,或者是1 的话,那么最后一位加上 8 后除以10,那么还是0 ,但是如果是大于等于2,那么 就是1了
如果最后一位是1的时候,需要加上b+1 , 如果不是1的话,就不需要,所以上面的公式可以整理成为
((a + 8 )/10 )* m + (a %10 == 1) * (b +1 )