整数中1出现的次数(从1到n整数中1出现的次数)

题目

求出 1 ~ 13的整数中1出现的次数,并算出100 ~ 1300的整数中1出现的次数?为此他特别数了一下1 ~ 13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。


我的想法

我的想法是,每一次求一个位置上的1的个数,第一轮先求个位上的1出现的个数,第二轮求十位上1出现的个数,以此类推...这样就能保证每个位置上的1都数了一次,并且不会出现多次重复数的情况。现在以其中的某一轮循环为例:假设现在有一个数 n = abcd(a,b,c,d分别表示0 ~ 9中的任意数)。我们本次循环要数的是b所在位置上1出现的个数。也就是要求满足X1XX这个样子的数的个数。我们可以将abcd分成两个部分,一部分在b前面即a,另一部分在b后面即cd。我们可以很容易的想到这样的关系(用x表示a中的取值,如a=7,x的取值为0 ~ 7,yz表示cd中的取值)
1.当x != a时,1个x对应100个yz,即0 ~ 99。比如,当x == 0时,yz可以是00 ~ 99
2.当x == a时,情况比较特殊,此时,我们不能保证b一定能取到1,所以要对b进行分情况讨论

当b > 1时,一个x还是对应100个xy
当b == 1时,一个x只能对应cd+1个xy,比如cd=17,那么就有xy的取值为00 ~ 17,18种可能
当b < 1时,因为b取不到1,所以这个这时不可能有满足x1xx的数

这种做法同时也适用于求2 ~ 9出现的次数


代码如下

public int NumberOf1Between1AndN_Solution(int n) {

    int cur;			//每轮循环求cur位置上的1的个数
    int result = 0;		//统计出现的总次数
    int mul = 1;		//用来记录cur位置处于那个位置,个位,十位,百位...
    int input = n;		//保存输入,便于求出去掉cur前的若干个数字后的值
    int target = 1;		//取值1-9,表示求的target出现的个数,如本题为1

    while (n != 0) {
        cur = n % 10;
        n /= 10;

        result += n * mul;

        if (cur > target) {
            result += 1 * mul;
        }
        else if (cur == target) {
            result += input % mul + 1;
        }

        mul *= 10;
    }

    return result;
}

posted @ 2018-05-12 11:19  _weirdly  阅读(563)  评论(0编辑  收藏  举报