JZ43 整数中1出现的次数(从1到n整数中1出现的次数)

136 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看活动详情

Day38 2023/02/13

题目链接

难度:中等

题目

输入一个整数 n ,求 1~n 这 n 个整数的十进制表示中 1 出现的次数
例如, 1~13 中包含 1 的数字有 1 、 10 、 11 、 12 、 13 因此共出现 6 次

注意:11 这种情况算两次

数据范围: 1≤n≤30000 

进阶:空间复杂度  O(1)  ,时间复杂度  O(lognn)

示例

输入:13
返回值:6
说明:1-13中包含1的数字有1, 10, 11, 12, 13, 其中11算两次

思路


我们看到题目要求 “输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数”。其实就是求从1-n这n个数中,每一个数的计数位上出现的1的个数的总和,所以最简单的方法就是暴力解法,直接从1-n开始遍历,对每个数进行数位的拆解,然后统计1的个数就ok 了。
具体步骤:

  1. 从1-n进行遍历,然后对每个数字进行数为的拆解。
  2. 如果该计数位等于1,结果就+1,否则继续循环。

关键点


  • 数位的拆解是通过模运算和除法实现的。

算法实现


c++代码实现-暴力解法

class Solution {
  public:
    int NumberOf1Between1AndN_Solution(int n) {
        int num = 0; //统计1出现次数
        for (int i = 1; i <= n; ++i) { 
            if (i % 10 == 1) { //拆解计数位
                ++num; //等于1,则结果加1
            }
            int a = i / 10; //去掉最后一位
            for (; a > 0; a = a / 10) {
                if (a % 10 == 1) {
                    ++num;
                }
            }
        }
        return num; //最后返回结果
    }
};
  • 时间复杂度 O(n2)O(n^2) --- 当数据比较大的时候,嵌套双层循环几乎每一层都循环n次,其中n为输入的整数
  • 空间复杂度 O(1)O(1) --- 没有额外的辅助空间

总结

-针对本题使用暴力解法是最好理解的,但是当n取值特别大的时候,时间复杂度较高。其实本题还有用数学相关的知识点去解题,并获得更低的时间复杂度。