《剑指Offer》:从1到n整数中1出现的次数,简易解法,O(logn)

1、题目来源:

       最近在刷题,《剑指offer》当然是不二之选,但是书中偶尔有些解法并不完美。比如第32题,书中给出的解法过于繁复,想在面试极短的时间内完整写出,难度较大。上网搜索了一下其他解法,讲解的都不太容易理解,故写了此篇博客,记录一下自己的理解。

2、题目描述:

      输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1的数字有1,10,11和12,1一共出现了5次。

3、具体解法:

      暴力的解法一个一个数字考虑,时间复杂度过大,肯定是打动不了面试官,拿下sp的。我们从位的角度来考虑,以三位数534为例。

      情况一:个位上出现1

                                                              è¿éåå¾çæè¿°

      此时将个位固定为1,base记为1。那么考虑百位的取值为0、1、2、3、4五个数,十位可取0-9十个数,一共有5*10=50种组合。再考虑百位取5,此时因为十位有限制,最大不过3,所以有3+1种组合(501,511,521,531),故总共有count = 53 +1 = 54种(即count = round*base + base)组合。

       如果个位(即weight)等于1,n = 531,情况同上,count = 53 + 0 + 1 = round*base + 1 + former;(此时former = 0)

       如果个位等于0,n = 530,则531取不到,此时count = 53 = round*base;

     情况二:十位上出现1

                                       è¿éåå¾çæè¿°

      此时将十位固定为1,base = base * 10 = 10。

      如果weight > 1,如weight = 3,n =534,此时考虑百位的取值为0、1、2、3、4、5六个数,个位可取0-9十个数,一共有count = 6*10=round*base + base = 60种组合。

      如果weight =1,n = 514,此时当百位为5时,个位就不能取0-9所有数了,如取5,则515就超过514了。此时考虑former的值,个位有0,1,2,3,4五种取法。故count = 5*10 + 4 + 1 = round * base + former + 1; 

      如果weight = 0,n = 504,此时当百位为5时,十位取不到1,故count = round*base = 5 * 10 = 50;

总结:

     对其它位来说,记每一位的权值为base,位值为weight,该位之前的数是former,则

  • 若weight为0,则1出现次数为round*base
  • 若weight为1,则1出现次数为 round * base + former + 1
  • 若weight大于1,则1出现次数为round*base + base

 

4、代码(java)

class Solution {
    public int countDigitOne(int n) {
        if (n < 1){
            return 0;
        }
        int count = 0;
        int base = 1;
        int round = n;
        while(round > 0){
            int weight = round % 10;
            round = round / 10;
            count = count + round * base;
            if (weight == 1){
                count = count + 1 + n%base;
            }else if (weight > 1){
                count = count + base;
            }
            base = base * 10;
        }
        return count;
    }
}

5、运行结果

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值