剑指Offer(从 1 到 N 中 1 出现的次数)java实现

剑指offer上有一题:从1到N中1出现的次数,

比如N 为12时,出现1的数字有1,10,11,12,那么1总共出现5次。

思路:

使用递归思想,先考虑普通输入N = 345,从1 -- 345可以分拆为1 -- 45和46 -- 345(可以认为是分分治思想)

分别求1 -- 45 和 46 -- 345中1出现的次数

  • 对1 -- 45也可以采用上述方法进行拆分为1 -- 5和6 -- 45,这就是递归的部分
  • 对46--345这部分,我们需要知道有多个1: 

            1、首先关注345最高位3,因为大于1,所以存在100--199 属于46--345,也就是有10^(n - 1)个1(n为345的位数)。

            2、对于345,因为first > 1(first为最高位数值),这样按照上一步来计算。当first == 1时,最高位为1的出现次数从100--145,为46次,也就是非最高位数值+1。

            3、然后非最高位也可能存在1,如x1x,xx1,对x1x,最高位的x可以取1,2,3,个位的x可以取0--9,所以有3 * (10^1)种,同理xx1也有3*(10^1)种。所以非最高位存在1的总数为 2 * 3 *(10^1)个,抽象为(n - 1)*first *(10 ^(n - 2)),n为345的位数。

             4、求完46 -- 345中1的个数,然后求1--45中1的个数,这是就是递归了,1---45可以拆分为1--5和6--45,然后6--45执行上述的计算,1--5继续递归。

             5、递归结束的条件是N的位数n == 1,这时候需要判断这个传入递归函数的N,if(N >= 1)return 1; if(N == 0)return 0;

源代码:

public static int countDigitOne(int n) {
    if(n < 0)
        return 0;     //异常处理
    char[] ch = String.valueOf(n).toCharArray();
    return numOfOne(ch, 0);
}

private static int numOfOne(char[] ch, int index) {
     int first = ch[index] - '0';                //求取当下最高位的数值
     if(ch.length - index == 1 && first == 0)    // 递归条件判断,输入值是否为1位且为0
         return 0;
     if(ch.length - index == 1 && first >= 1)    //输入值是否为1位且大于等于1
         return 1;
     int numOtherOne = 0;
     if(first > 1)                             //求取最高位为1的数字出现次数
         numOtherOne = power(ch.length - index - 1);
   
        
     if(first == 1)                             //求取最高位为1的数字出现次数
         numOtherOne = power1(ch, index);
     int numLowOne = first * (ch.length - index - 1) * power(ch.length - index - 2); //求取非最高位为1的数字出现次数
     int numRecurive = numOfOne(ch, index + 1);      //递归
     return numOtherOne + numLowOne + numRecurive;
}

private static int power(int n) {  //求取10^n
     int m = 1;
     for(int i = 0; i < n; i++)
         m *= 10;
     return m;
}

private static int power1(char[] ch, int index) {  //求取子字符数组的数值
     String s = String.valueOf(ch).substring(index + 1);
     return Integer.valueOf(s) + 1;
}

复杂度分析:

  • 时间复杂度:O(log(N))  

每一次递归的时间复杂度为O(1),一个数字N有log(N)位,所以递归深度为log(N)

总的时间复杂度O(log(N))。

  • 空间复杂度:需要创建一个字符数组来存放数字N的log(N)位。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值