本人太菜没有看懂大部分人推崇的方法,试了下数学归纳法,发现也不错。
先来做如下归纳:
0-9中有1个1;
10-19中有1+10=11个1;
20-29中有1个1;
...
0-99中有11*1+1*9=20个1;
100-199中有20+100=120个1;(希望大家认真理解为什么是+100)
0-999中有20*9+120=20*10+100=300个1(此处20为0-99中1的个数,100为10^2);
0-9999中有300*10+1000=4000个1(此处300为0-999中1的个数,1000为10^3)。
我们再回头整理下思路:
0-9(1个9)中有1*10^0个1;
0-99(2个9)中有2*10^1个1;
0-999(3个9)中有3*10^2个1;
0-9999(4个9)中有4*10^3个1;
...
0-999999999(9个9)中有9*10^8个1;
0-9999999999(10个9)中有(9*10^8)*10+10^9=10*10^9个1;
此时10个9已大于java语言中int的最大取值,无需继续往下推。
现在开始归纳总结(以1314521为例):
归纳:
0-999999(6个9)--> 6*10^5
10^6-1299999------>先拆分下再看
->0-99999 -->5*10^4
->10^5-199999 -->5*10^4+10^5
->2*10^5-299999 -->5*10^4
综上三行:
10^6-1299999 --> 3*5*10^4+10^5+(299999+1)
这里加299999+1是因为最前方的1一直存在,以后()中为这一部分。也可以暂且不管这一部分(后面算法思路中就是将这一部分统一计算),考虑到从左侧开始第一个1在最后加上314521+1,考虑到从左侧开始第三个1在最后加上4521+1,剩下的那个1在个位上,无需考虑。
依次类推
13*10^5-1309999 -->4*10^3+(9999+1)
131*10^4-1313999 -->3*10^2*4+10^3+(3999+1)*2 (这里*2是因为第二个1也开始起作用)
1314000-1314499 -->5*2*10^1+100+(499+1)*2
1314500-1314519 -->2*10^0+10+(19+1)*2
1314520-1314521 -->0*10^-1+1+(1+1)*2
至此,对上方所有结果求和,可得1175457为正确结果。
算法思路:
1、获取1314521中7位数字的值与对应的阶数(阶数并非准确称呼):
1,0阶
2,1阶
5,2阶
4,3阶
1,4阶
3,5阶
1,6阶
看到这里,再跟1314521对比,想必大家可以明白在下"阶数"所指。
这里定义了一个类Inner,其中num代表1314521中各个取值,n代表阶数。
2、遍历,各位数字,如下:
若值num>1,结果中加上n*num*10^(n-1)+10^n
若值num=1,结果中加上n*10^(n-1)
若值num=0,不加
3、找1:
1314521中含有3个1
从左往右第一位需要在结果中补加上314522;
第二位需要在结果中补加上4522;
第三位需要在结果中补加上0;
因此,代码如下:

   public class Inner {
        int num; // 当前阶的值 
        int n;  // 阶次 10^n
        public Inner(int num, int n) {
            this.num = num;
            this.n = n;
        }
    }
    public int NumberOf1Between1AndN_Solution(int n) {
        int res = 0; // 最终结果
        ArrayList<Inner> temp = new ArrayList<Inner>();
        // 计算各阶次及值
        for (int i = 1, j = 0; i <= n; i *= 10, j ++) {
            int b = (n / i) % 10;
            temp.add(new Inner(b, j));
        }
                /**
                 * 遍历
                 **/
        for(Inner inner : temp) {
            if (inner.n == 0) {
                if (inner.num >= 1) {
                    res += 1;
                }
            } else if (inner.num > 1) {
                res += (inner.n * inner.num * Math.pow(10, inner.n - 1) + Math.pow(10, inner.n));
            } else if (inner.num == 1) {
                res += (inner.n * Math.pow(10, inner.n - 1));
            } else {

            }
        }
        /**
         * 找1
         */
        for (int i = 0; i < temp.size(); i++) {
            if (temp.get(i).num == 1 && temp.get(i).n != 0) {
                for (Inner inner : temp) {
                    if (inner.n < temp.get(i).n) {
                        res += inner.num * Math.pow(10, inner.n);
                    }
                }
                res += 1;
            }
        }
        return res;
    }

整理的比较匆忙,如有不当指出,欢迎大家批评指正。谢谢!