统计1到N之间所有数字中1的个数

本文中的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 )

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值