IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> LeetCode 233. Number of Digit One【计数模拟】困难 -> 正文阅读

[数据结构与算法]LeetCode 233. Number of Digit One【计数模拟】困难

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,这个截止期限可能是永远。

在这一系列刷题文章中,不仅讲解多种解体思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时还会总结相应的算法模板。为了方便在PC上运行调试、分享代码文件,我还将建立相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目总结、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

Example 1:

Input: n = 13
Output: 6

Example 2:

Input: n = 0
Output: 0

Constraints:

  • 0 <= n <= 109

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


解法 数位DP简化的计数模拟

这一题其实是简化版,是一道「数位DP」模板题P1980 [NOIP2013 普及组] 计数问题的简化,不过那道NOIP题效率最高的解法也还是计数模拟,见这篇文章。做过那道题后再做这道题,会轻松很多。

回到本题,是时候重温计数原理了:

  • 加法原理:简单来说就是分类。做一件事情,完成它有不重不漏 n n n 大类解法,第一大类有 m 1 m_1 m1? 种方法,第二大类有 m 2 m_2 m2? 种方法,……,第 n n n 大类有 m n m_n mn? 种方法,那么完成这件事共有 m 1 + m 2 + … … + m n m_1+m_2+……+m_n m1?+m2?++mn? 种方法。
  • 乘法原理:简单来说就是分步。做第一步有 m 1 m_1 m1? 种不同的方法,做第二步有 m 2 m_2 m2? 种不同的方法,……,做第 n n n 步有 m n m_n mn? 种不同的方法。那么完成这件事共有 m 1 × m 2 × m 3 × … × m n m_1×m_2×m_3×…×m_n m1?×m2?×m3?××mn? 种不同的方法。

本题计算 [ 1 , n ] [1, n] [1,n] 的所有整数中 1 1 1 出现的个数,主要运用加法分类原理,即分别计算所有整数中出现在个位、十位、百位……的 1 1 1 的个数,然后加总得到结果。现在的问题是,如何统计 1 1 1 在第 i i i 位出现的次数

假设一个五位的数 n = a b c d e n = abcde n=abcde ,我们需要统计第 3 3 3 位中 1 1 1 出现的次数,即计算满足 _ ? _ ? 1 ? _ ? _ \_\ \_\ 1\ \_\ \_ _?_?1?_?_ 形式且 1 ≤ _ ? _ ? 1 ? _ ? _ ≤ a b c d e 1 \le \_\ \_\ 1\ \_\ \_ \le abcde 1_?_?1?_?_abcde 的整数有多少个,我们将这一条件简称为「限定」。下面主要对 c c c 的大小(和 c c c 前一部分的大小)进行分类讨论:

  • c > 1 c \gt 1 c>1 时:
    • c c c 前一部分 < a b < ab <ab 时,即范围为 [ 0 , a b ) [0, ab) [0,ab) ,必然满足「限定」,因此后一部分可以任意取值,范围为 [ 0 , 99 ] [0, 99] [0,99] 。根据乘法原理,此时第 3 3 3 位中 1 1 1 出现的次数加上 a b ? 100 ab * 100 ab?100
    • c c c 前一部分 = a b = ab =ab 时,由于 c > 1 c > 1 c>1 ,也必然满足「限定」,因此后一部分可以任意取值,范围为 [ 0 , 99 ] [0, 99] [0,99] ,此时第 3 3 3 位中 1 1 1 出现的次数加上 100 100 100
    • c c c 前一部分 > a b > ab >ab 时,必然不满足「限定」。
  • c = 1 c = 1 c=1 时:
    • c c c 前一部分 < a b < ab <ab 时,即范围为 [ 0 , a b ) [0, ab) [0,ab) ,必然满足「限定」,因此后一部分可以任意取值,范围为 [ 0 , 99 ] [0, 99] [0,99] 。根据乘法原理,此时第 3 3 3 位中 1 1 1 出现的次数加上 a b ? 100 ab * 100 ab?100
    • c c c 前一部分 = a b = ab =ab 时,由于 c = 1 c = 1 c=1 ,只有后一部分取值在范围 [ 0 , d e ] [0, de] [0,de] 时才满足「限定」,此时第 3 3 3 位中 1 1 1 出现的次数加上 d e + 1 de + 1 de+1
    • c c c 前一部分 > a b > ab >ab 时,必然不满足「限定」。
  • c = 0 c = 0 c=0 时:
    • c c c 前一部分 < a b < ab <ab 时,即范围为 [ 0 , a b ) [0, ab) [0,ab) ,必然满足「限定」,因此后一部分可以任意取值,范围为 [ 0 , 99 ] [0, 99] [0,99] 。根据乘法原理,此时第 3 3 3 位中 1 1 1 出现的次数加上 a b ? 100 ab * 100 ab?100
    • c c c 前一部分 = a b = ab =ab 时,由于 c = 0 c = 0 c=0 ,无论后一部分如何取值,都不能满足「限定」;
    • c c c 前一部分 > a b > ab >ab 时,必然不满足「限定」。

或者主要对 c c c 前一部分的大小进行分类讨论,简要归纳如下:

  • c c c 前一部分 < a b < ab <ab 时,无论如何都满足「限定」,因此后一部分可以任意取值,此时第 3 3 3 位中 1 1 1 出现的次数加上 a b ? 100 ab * 100 ab?100
  • c c c 前一部分 = a b = ab =ab 时,是否满足「限定」取决于 c c c 的大小
    • c > 1 c > 1 c>1 时,必然满足「限定」,因此后一部分可以任意取值,此时第 3 3 3 位中 1 1 1 出现的次数加上 100 100 100
    • c = 1 c = 1 c=1 时,只有后一部分取值在范围 [ 0 , d e ] [0, de] [0,de] 时才满足「限定」,此时第 3 3 3 位中 1 1 1 出现的次数加上 d e + 1 de + 1 de+1
    • c = 0 c = 0 c=0 时,无论后一部分如何取值,都不能满足「限定」;
  • c c c 前一部分 > a b > ab >ab 时,必然不满足「限定」。

最后实现的代码如下:

class Solution {
public:
    int countDigitOne(int n) { 
        int ans = 0;
        long long r = 1;
        while (r <= n) { //分别计算个、十、百......千位上1出现的次数,再求和
            int a = n / (r * 10), b = n / r % 10, c = n % r;
            switch (b) {
                case 0: ans += a * r; break;
                case 1: ans += a * r + c + 1; break;
                default: ans += (a + 1) * r; break;
            }
            r *= 10; //不然r可能溢出
        } 
        return ans;
    } 
};

时间复杂度为 O ( lg ? n ) O(\lg n) O(lgn) ,空间复杂度为 O ( 1 ) O(1) O(1) 。运行效率如下:

执行用时:0 ms, 在所有 C++ 提交中击败了100.00% 的用户
内存消耗:5.8 MB, 在所有 C++ 提交中击败了73.12% 的用户
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-18 12:56:50  更:2021-08-18 12:57:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:55:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码