数字 1 的个数

1 题目描述

题目链接
在这里插入图片描述

2 题解

解题思路: 将1~n 的个位、十位、百位、…的1出现次数相加,即为1出现的总次数。

设数字n是个x位数,记n的第i位为 n i n_i ni,则可将n写为 n x n x − 1 . . . n 2 n 1 n_xn_{x-1}...n_2n_1 nxnx1...n2n1:

  1. 称" n i n_i ni"为当前位,记为cur
  2. 将" n i − 1 n i − 1 . . . n 2 n 1 n_{i-1}n_{i-1}...n_2n_1 ni1ni1...n2n1"称为低位,记为low
  3. 将" n x n x − 1 . . . n i + 2 n i + 1 n_xn_{x-1}...n_{i+2}n_{i+1} nxnx1...ni+2ni+1"称为高位,记为high
  4. 1 0 i 10^i 10i称为位因子,记为digit

某位中1出现次数的计算方法:
根据当前位cur值的不同,分为以下三种情况:

1. 当 cur=0 时:此时1的出现次数只由高位high决定,计算公式为:
h i g h ∗ d i g i t high * digit highdigit
如下图所示,以 n=2304为例,求 digit=10(即十位)的 1出现次数。

在这里插入图片描述
2. 当 cur=1 时:此位1的出现次数由高位high和低位low决定,计算公式为:
h i g h ∗ d i g i t + l o w + 1 high * digit+low+1 highdigit+low+1

如下图所示,以 n=2314 为例,求 digit = 10(即十位)的1出现次数。

在这里插入图片描述
3. 当 cur = 2,3,…,9时:此位1的出现次数只由高位high决定,计算公式为:
( h i g h + 1 ) ∗ d i g i t (high+1)*digit high+1digit

如下图所示,以 n = 2324 为例,求digit = 10(即十位)的1出现次数。

在这里插入图片描述
变量递推公式:

 设计按照"个位、十位、…"的顺序计算,则 high / cur / low / digit:

high = n / 10;
cur = n % 10;
low = 0;
digit = 1; // 个位

因此,从个位到最高位的变量递推公式为:

while high!=0 or cur!=0:// 当high和cur同时为0时,说明已经越过最高位,因此跳出
	low +=cur*digit; // 将cur加入low,组成下轮low
	cur = high % 10; // 下轮cur是本轮high的最低位
	high /=10;  // 将本轮high最低位删除,得到下轮high
	digit *=10; // 位因子每轮 ✖ 10

复杂度分析:

  1. 时间复杂度O(log n) : 循环内的计算操作使用O(1) 时间;循环次数为数字n的位数,即 l o g 10 n log_{10}n log10n,因此循环使用O(log n)时间。
  2. 空间复杂度O(1) : 几个变量使用常数大小的额外空间。

2.1 案例分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2 核心代码

class Solution {
public:
    int countDigitOne(int n) {
        if(n<0)
            return 0;
        long digit=1,res=0;
        int high,cur,low;
        high=n/10,cur=n%10;low=0;
        while(high!=0 or cur!=0){
            if(cur==0)
                res+=high*digit;
            else if(cur==1)
                res+=high*digit+low+1;
            else
                res+=high*digit+digit;
            low+=cur*digit;
            cur=high%10;
            high/=10;
            digit*=10;
        }
        return res;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值