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

文章目录

  • 一【题目类别】
  • 二【题目难度】
  • 三【题目编号】
  • 四【题目描述】
  • 五【题目示例】
  • 六【解题思路】
  • 七【题目提示】
  • 八【时间频度】
  • 九【代码实现】
  • 十【提交结果】

一【题目类别】

  • 数学

二【题目难度】

  • 困难

三【题目编号】

  • 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语言版
    【LeetCode每日一题】——233.数字 1 的个数_第1张图片

  2. C语言版
    【LeetCode每日一题】——233.数字 1 的个数_第2张图片

  3. Python语言版
    【LeetCode每日一题】——233.数字 1 的个数_第3张图片

你可能感兴趣的:(LeetCode,leetcode,算法,数据结构,数学,c语言)