233. 数字 1 的个数

164 阅读2分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

233. 数字 1 的个数

给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。

示例 1:

输入:n = 13 输出:6 示例 2:

输入:n = 0 输出:0

解题思路

根据题目要求,我们需要统计 [0,n] 范围内所有整数中,数字 1 出现的个数。由于 n 的范围最大为 10^9 ,它是一个 10 位整数,因此我们可以考虑枚举每一个数位,分别统计该数位上数字 1 出现的次数,最后将所有数位统计出的次数进行累加即可得到答案

bef代表当前位前面的数字大小
w代表当前位的权重,例如10,100,1000
n代表当前位后面的数字大小
            if (当前位>1)
            {
             对答案贡献:(n+1)*w;
            }else if (当前位==1)
            {
              对答案贡献:n*w+bef+1;
            }else  对答案贡献:n*w;

正确性证明

例如:对于n=3015, 我们先想象有一个自行车密码锁(这个比喻来自@ryan0414),一共有四位,每一位可单独滚动。为了计算十位出现1的次数,我们考虑三种情况:

  • 固定个位1,个位为1的数字组成的可能是[000-301]1,所以共有302个数字个位数为1,所以对答案贡献302个1。
  • 固定十位1,十位为1的数字组成为[00-29]1[0-9]和[30]1[0-5],所以共有30 * 10+6个数字个位数为1,所以对答案贡献306个1。
  • 百位为1的数字组成为[0-2]1[00-99],所以共有300个数字个位数为1,所以对答案贡献200个1。
  • 千位数字为1很明显只有1000个数字,1[000-999],所以对答案贡献1000个1。

所以最后的总和为1908

代码

class Solution {
  public int countDigitOne(int n) {

        int bef=0,res=0,w=1;
        while (n>0){
            int cur=n%10;
            n/=10;
            if (cur>1)
            {
             res+=(n+1)*w;
            }else if (cur==1)
            {
                res+=n*w+bef+1;
            }else res+=n*w;

            bef+=cur*w;
            w*=10;
        }
        return res;

    }
}