【剑指offer-Java版】32从1到n的整数中1出现的次数

1到n中1出现的次数:
书上的讲解实在是没看懂,翻翻作者的博客找到了一个通俗解法,自己又补充了一些思考细节,全在注释里面了


    public class _Q32<T> {

    public static void main(String[] args) {

        /* 5 6 16 20 */
        System.out.println(NumberOf1(12));
        System.out.println(NumberOf1(13));
        System.out.println(NumberOf1(55));
        System.out.println(NumberOf1(99));
    }

    /**
     * @comment 思路:
     * 书中的例子并没有看懂,所以查找了作者的博客,博客中有关于该问题的通俗解法,时间复杂度为O(logn)
     * 
     * 作者的博客地址: http://zhedahht.blog.163.com/blog/static/25411174200732494452636/
     * 
     * 该思路的举例分析:
     * 我是按照各位做统计的,某位左侧代表这个循环体出现了几次,右侧代表这个体中1出现了多少遍,如:
     * 30143:
     * 由于3>1,则个位上出现1的次数为(3014+1)*1  -- 当个位为1的时候,可以有 1 11 21 ... 30141这么多种
     * 由于4>1,则十位上出现1的次数为(301+1)*10  -- 当十位为1的时候,可以有 10 11 12 .. 19 110 111 ...119 ... 29119 ... 30113
     * 由于1=1,则百位上出现1次数为(30+0)*100+(43+1) -- 当百位为1的时候,可以有 100 101 .. 199 1100...29199 ... 30143
     * 由于0<1,则千位上出现1次数为(3+0)*1000 -- 千位为0那么只能是 1000 1001 ... 1999 11000 11001 ... 11999 ... 21999
     *
     *  注:以百位为例,百位出现1100~199,*100的意思为单步出现了100~199100次,*30是因为出现了30100~199,
     *  +(43+1)是因为最后一次301**不完整导致
     *  
     * 那么有些同学可能会觉得这样会不会出现重复统计的情况,比如针对上述的例子,如果取 11111岂不是会被计算5次
     * 其实题目的意思是求1出现的次数,也就是不管这个数是多少位的,比如11这个数1出现次数是2
     * 而上述的算法计算的时候就是针对每一位进行统计的,所以不存在重复计数的问题
     * 
     * 有了这样的思路之后,剩下的就是抽象出可以进行编码的表达式,如下:
     * 假设当前考虑的位是第k位(从右向左,从0计数),原数为n
     * 那么如果当前第k位为0     :(n/pow(10, k+1) + 0)*pow(10, k)
     * 那么如果当前第k位为1     :(n/pow(10, k+1) + 0)*pow(10, k) + (n%pow(10, k) + 1)
     * 那么如果当前第k位大于1 :(n/pow(10, k+1) + 1)*pow(10, k) 
     * 依次对n的每一位进行计算并累加,时间复杂度是O(logn)
     * 
     * 此处暂时就没有考虑大数问题 -- 需要的时候直接改为long或者BigInteger就好了
     * 
     * @param n
     * @return   
     * @return int  
     * @throws
     * @date 2016416日 下午8:36:48
     */
    public static int NumberOf1(int n){
        if(n <= 0) return 0;

        int result = 0;
        int nn = n;
        int k = 0;
        int cur = 0;

        while(nn > 0){
            cur = nn % 10;
            nn = nn / 10;

            switch (cur) {
            case 0: // == 0
                result += n / (int) Math.pow(10, k + 1) * (int) Math.pow(10, k);
                break;
            case 1: // == 1
                result += n / (int) Math.pow(10, k + 1) * (int) Math.pow(10, k) + (n % (int) Math.pow(10, k) + 1);
                break;
            default: // > 1
                result += (n / (int) Math.pow(10, k + 1) + 1) * (int) Math.pow(10, k);
                break;
            }

            k++;
        }

        return result;
    }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值