【数学】——1~n 整数中 1 出现的次数

198 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

题目

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。

例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

难度:hard

思路

1.首先1~n这n个整数的1出现的个数可以看成每个位上1出现个数的和例如个位上面1出现的个数+十位上面1出现的个数+百位上1出现的个数...

2.将每个位上面的数分成3中情况

以数字21034为例,cur表示当前所在位置上面的数,left表示cur左边部分的数,right表示cur右边部分的数,

①cur大于1的情况

image.png

由于十位上面的数为3大于1,那么十位上面的为1可以组成的数字为:

left部分可以取到的数为 0 ~ 210,right部分可以取到的数为 0 ~ 10

那么就是:(left+1)*10个数

②cur小于1的情况(就是cur==0)

image.png

由于百位上面的数为0小于1,那么百位上面为1可以组成的数字为:

left部分可以取到的数为0 ~ 20(因为如果百位取到1的话那么211??就大于原来的数,所以取不到21)

right部分可以取到的数为 0 ~ 100

那么就是: left * 100 个数

③cur 等于 1的情况

image.png

那么千位上面为1可以组成的数字为:

left部分可以取到的数为 0 ~ 2,当left!=2的时候right可以取到0 ~ 100,当left == 2的时候right只能取到0~right(这是因为21035比n大)

那么就是:( left * 1000 + right + 1) 个数

注意下结束条件为: left != 0 || cur != 0

代码

class Solution {
    public int countDigitOne(int n) {
        int left = n / 10;
        int cur = n % 10;
        int right = 0;
        int res = 0;
        int base = 1;
        while (cur != 0 || left != 0) {
            if (cur > 1) {
                res += (left + 1) * base;
            } else if (cur < 1) {
                res += left * base;
            } else if (cur == 1) {
                res += left * base + right + 1;
            }
            right += cur * base;
            cur = left % 10;
            left = left / 10;
            base *= 10;

        }
        return res;
    }
}