整数中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;
}