【LeetCode每日一题】——233.数字 1 的个数

文章介绍了编程题目‘数字1的个数’,该题目要求计算小于等于给定整数n的所有非负整数中数字1的总数。解题策略是通过分析每个数位上1的出现规律,利用分治思想将问题分解,然后分别计算个位、十位、百位等的1的个数,最终合并结果。给出的解决方案具有O(logn)的时间复杂度,并提供了Java、C和Python三种语言的代码实现。
摘要由CSDN通过智能技术生成

一【题目类别】

  • 数学

二【题目难度】

  • 困难

三【题目编号】

  • 233.数字 1 的个数

四【题目描述】

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

五【题目示例】

  • 示例 1:

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

    • 输入:n = 0
    • 输出:0

六【解题思路】

  • 本题有一定难度,我第一次使用暴力解法, O ( n ) O(n) O(n)的时间复杂度,逐一判断每一个数字1的个数,最后超时了,显然需要换一个思路
  • 为了降低时间复杂度,就不能一个一个的处理,而是要分批处理,主要思路是求出个、十、百……每一位1的个数,最后求和就可以了
  • 当数位为 1 0 k 10^k 10k时(可能是个、十、百……任意一位),最后的 k k k位数字每 1 0 k + 1 10^{k+1} 10k+1个数字就会循环一次,而且其中包括 1 0 k 10^k 10k个1,那我们就要求 n n n中有多少个这样的循环,可用除法实现: ⌊ n 1 0 k + 1 ⌋ \left\lfloor\frac{n}{10^{k+1}}\right\rfloor 10k+1n,这样这一部分1的个数就是: ⌊ n 1 0 k + 1 ⌋ × 1 0 k \left\lfloor\frac{n}{10^{k+1}}\right\rfloor × 10^k 10k+1n×10k
  • 刚才处理了在循环内1的个数,那么不在循环内的呢?也就是剩余的 n   m o d   1 0 k + 1 n \bmod 10^{k+1} nmod10k+1个数,这一部分1的个数应为 n   m o d   1 0 k + 1 − 1 0 k + 1 n \bmod 10^{k+1} - 10^k + 1 nmod10k+110k+1,剩余的这些数有几种情况:
    • 上式的值小于0,那么就将此值调整为1出现0次,说明1没出现过
    • 上式的值大于 1 0 k 10^k 10k,说明1出现了 1 0 k 10^k 10k
    • 还有另一个不确定的阈值,要根据位数去判断,如果上式的值不仅大于 1 0 k 10^k 10k,还大于此阈值,说明1出现的次数最多就是此阈值对应的出现次数,所以应该在两者中取最小
  • 根据以上思路就可得到计算公式:
    ⌊ n 1 0 k + 1 ⌋ × 1 0 k + min ⁡ ( max ⁡ ( n   m o d   1 0 k + 1 − 1 0 k + 1 , 0 ) , 1 0 k ) \left\lfloor\frac{n}{10^{k+1}}\right\rfloor \times 10^{k}+\min \left(\max \left(n \bmod 10^{k+1}-10^{k}+1,0\right), 10^{k}\right) 10k+1n×10k+min(max(nmod10k+110k+1,0),10k)

七【题目提示】

  • 0 < = n < = 1 0 9 0 <= n <= 10^{9} 0<=n<=109

八【时间频度】

  • 时间复杂度: O ( l o g n ) O(logn) O(logn),其中 n n n为传入参数的大小
  • 空间复杂度: O ( 1 ) O(1) O(1)

九【代码实现】

  1. Java语言版
class Solution {
    public int countDigitOne(int n) {
        long mul = 1;
        int res = 0;
        for(int k = 0;mul<=n;k++){
            res += (n / (mul * 10)) * mul + Math.min(Math.max(n % (mul * 10) - mul + 1,0),mul);
            mul *= 10;
        }
        return res;
    }
}
  1. C语言版
int countDigitOne(int n)
{
    long mul = 1;
    int res = 0;
    while(mul <= n)
    {
        res += (n / (mul * 10)) * mul + fmin(fmax(n % (mul * 10) - mul + 1,0),mul);
        mul *= 10;
    }
    return res;
}
  1. Python版
class Solution:
    def countDigitOne(self, n: int) -> int:
        mul = 1
        res = 0
        while mul <= n:
            res += (n // (mul * 10)) * mul + min(max(n % (mul * 10) - mul + 1,0),mul)
            mul *= 10
        return res

十【提交结果】

  1. Java语言版
    在这里插入图片描述

  2. C语言版
    在这里插入图片描述

  3. Python语言版
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IronmanJay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值