求1~n这n个整数十进制表示中1出现的次数

文章目录

  • 题目
  • 思路
  • 代码
  • 复杂度分析


题目

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。

例如,输入12,那么1~12这些整数中包含1 的数字有1、10、11和12。可得1一共出现了5次。


思路

将个位、十位……每位1出现的次数加起来就是1一共出现的次数。

以12为例,个位上1出现了 2 次分别是 01,11(暂时不看11的十位)。

十位上1出现了 3 次,分别是10,11,12。

因此1~12中1一共出现了 2+3=5 次。

两位数不好找规律,我们以四位数为例。一个四位数十位上 1 出现的次数,与十位上的值有关。根据值不同,可分为三种情况,值为0,1,2~9:

我们通过三个不同四位数进行探讨,分别是 230423142324

我们将数字划分为三部分,当前位(cur),高位(high),以及低位(low),用digit表示当前处于哪个数位。

  1. cur = 0 时: 此位 1 的出现次数只由高位 high 决定,计算公式为:
high×digit

图源
详细分析:

对于2304来讲,十位出现1的范围:0010~2219 没有什么可多说的。

那么1出现的次数怎么算呢?

光看高位的话,00 ~ 22 总共有 23 种数字,也就是 001X ~ 221X 。而其中的 ‘X',有 0 ~ 9 总共 10 种取法,也就是说排列组合下来,可以构成有 23*10=230 个十位为1的数字,如下表:

highcurlow
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
1
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
  1. cur = 1 时: 此位 1 的出现次数由高位 high 和低位 low 共同决定,计算公式为:
high×digit+low+1

在这里插入图片描述
详细分析:

十位上1出现的次数怎么算呢?

出现 1 的数字范围: 0010 ~ 2314

光看高位的话,有 00 ~ 23 总共 24 种组合排列方法,但是! 对于 00 ~ 2223 种高位来讲,低位都有 0 ~ 9 总共 10 种排列组合 —— 0010 ~ 00192210 ~ 2219 ,但是 23 不同,其低位只有 0 ~ 4 五种排列组合 —— 2310 ~ 2314 。因此,可以构成 23*10+5=235 个十位为 1 的数字(23*10代表 【高位为00~22】 的所有数字,5代表 【高位为23】 的所有数字)。

  1. cur=2,3,⋯,9 时: 此位 1 的出现次数只由高位 high 决定,计算公式为:
(high+1)×digit

在这里插入图片描述
详细分析:

十位上1出现的次数怎么算呢?

此时与 cur=1 不同,cur=1 时出现的次数还需要看 low 的值,此时出现 1 的数字范围: 0010 ~ 2319 ,也就是说,高位为 23 时,低位也有 0 ~ 9 共计 10 种排列组合方法,与高位为 00 ~ 22 时一样,因此,cur=2~9 时,十位上 1 出现的次数为:24*10=240

上面各图源自jyd大佬


代码

class Solution {
public:int countDigitOne(int n) {long long digit = 1;int low = 0;int cur = n % 10;int high = n / 10;int sum = 0;while(high || cur){if(cur==0){sum += high * digit;}if(cur==1){sum += high*digit+low+1;}if(cur!=0 && cur!=1){sum += (high+1)*digit;}low += cur * digit;cur = high % 10;high /= 10;digit *= 10;}return sum;}
};

复杂度分析

时间复杂度 O(logn): 循环内的计算操作使用 O(1) 时间;循环次数为数字 n 的位数,即 log10n,因此循环使用 O(logn) 时间。

空间复杂度 O(1) : 几个变量使用常数大小的额外空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443788.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

求数字序列中的第n位对应的数字

文章目录题目思路代码复杂度分析致谢题目 数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。 请写一个函数&#xff0c…

一学就废的归并排序

文章目录其他与排序有关的文章原理代码实现复杂度分析其他与排序有关的文章 一学就废的三种简单排序【冒泡、插入、选择】 原理 归并排序(Merge sort): 归并排序对元素 递归地 进行 逐层折半分组,然后从最小分组开始&#xff0c…

树状数组的相关知识 及 求逆序对的运用

文章目录树状数组概念前缀和和区间和树状数组原理区间和——单点更新前缀和——区间查询完整代码离散化sort函数unique函数去重erase函数仅保留不重复元素通过树状数组求逆序对树状数组概念 树状数组又名二叉索引树,其查询与插入的复杂度都为 O(logN),其…

二叉搜索树相关知识及应用操作

文章目录概念查找二叉搜索树的第k大节点概念 二叉查找树(Binary Search Tree),(又名:二叉搜索树,二叉排序树)——它或者是一棵空树,或者是具有下列性质的二叉树: 若它的…

二叉树相关知识及求深度的代码实现

文章目录树二叉树满二叉树和完全二叉树二叉树的性质代码实现求二叉树的深度树 树是一种非线性的数据结构,它是由n个有限结点组成一个具有层次关系的集合。 树的相关名词: 根节点:没有前驱结点的结点。父节点,子节点&#xff1a…

大端小端存储模式详解及判断方法

文章目录大小端模式的概念两种模式出现原因两种模式的优劣大小端的应用情景判断机器的字节序大小端模式的概念 当我们查看数据在内存中的存储情况时,我们经常会发现一个很奇怪的现象,什么现象呢? int main() {int i 12;return 0; }数据在内…

Linux 内存管理 | 物理内存、内存碎片、伙伴系统、SLAB分配器

文章目录物理内存物理内存分配外部碎片内部碎片伙伴系统(buddy system)slab分配器物理内存 在Linux中,内核将物理内存划分为三个区域。 在解释DMA内存区域之前解释一下什么是DMA: DMA(直接存储器访问) 使用物理地址访问内存&am…

Linux 内存管理 | 虚拟内存管理:虚拟内存空间、虚拟内存分配

文章目录虚拟地址空间用户空间内核空间用户空间内存分配malloc内核空间内存分配kmallocvmalloc虚拟地址空间 在早期的计算机中,程序是直接运行在物理内存上的,而直接使用物理内存,通常都会面临以下几种问题: 内存缺乏访问控制&a…

Linux | 编译原理、gcc的命令参数、自动化构建工具 make/Makefile

文章目录编译原理预处理编译汇编链接gcc的常用命令参数make 和 Makefile 的概念make的运行通配符自动化变量伪目标.PHONE:【命令】编译原理 在解释 makefile 前,首先解释一下 .c 文件变成 .exe 文件要经过的四个步骤——预处理、编译、汇编和链接(参考来…

Linux | 进程概念、进程状态(僵尸进程、孤儿进程、守护进程)、进程地址空间

文章目录进程和程序操作系统如何控制和调度程序进程控制块–PCB子进程进程状态僵尸进程孤儿进程守护进程(精灵进程)进程地址空间引言页表进程和程序 程序: 一系列有序的指令集合(就是我们写的代码)。进程:…

Linux 进程控制 :进程创建,进程终止,进程等待,程序替换

文章目录进程创建进程等待程序替换进程终止进程创建 fork函数: 操作系统提供的创建新进程的方法,父进程通过调用 fork函数 创建一个子进程,父子进程代码共享,数据独有。 当调用 fork函数 时,通过 写时拷贝技术 来拷贝…

Linux 内存管理 | 连续分配方式 和 离散分配方式

文章目录前言连续分配单一连续分配分区式分配固定分区分配动态分区分配可重定位分区分配离散分配分段分页多级页表快表(TLB)段页式Linux前言 Linux 内存管理 | 虚拟内存管理:虚拟内存空间、虚拟内存分配 Linux 内存管理 | 物理内存、内存碎片、伙伴系统、SLAB分配器…

操作系统 | 用户态和内核态的切换(中断、系统调用与过程(库函数)调用)

文章目录中断过程调用系统调用过程调用和系统调用的区别中断 用户态、内核态之间的切换是怎么实现的? 用户态→内核态 是通过中断实现的。并且 中断是唯一途径 。核心态→用户态 的切换是通过执行一个特权指令,将程序状态字 (PSW) 的标志位设置为 用户态 。 中断…

管道实现父子进程的信息传递(二)【标准流和其文件描述符、fwrite函数、perror函数】

文章目录代码实现标准流 和 标准流文件描述符代码中用到的函数fwrite()perror()在复习进程间的通信方式时又写了一遍,和 管道实现父子进程的信息传递(一)【fork函数、pipe函数、write/read操作、wait函数】 的区别不是特别大,只是…

命名管道实现进程的信息传递【mkfifo函数、open函数】

文章目录代码实现mkfifo函数open函数代码实现 #include<fcntl.h> // open() #include<sys/wait.h> // wait() #include<sys/types.h> // mkfifo() #include<sys/stat.h> // mkfifo() #include<iostream> #include<unistd.h> // fork()usi…

Linux 进程 | 进程间的通信方式

文章目录管道匿名管道 pipe命名管道 FIFO共享内存共享内存的使用流程&#xff1a;消息队列信号量套接字在之前的博客中讲过&#xff0c;虚拟空间出现的其中一个目的就是解决 进程没有独立性&#xff0c;可能访问同一块物理内存 的问题。因为这种独立性&#xff0c;进程之间无法…

Linux网络编程 | socket介绍、网络字节序与主机字节序概念与两者的转换、TCP/UDP 连接中常用的 socket 接口

文章目录套接字socket 地址通用 socket 地址专用 socket 地址网络字节序与主机字节序地址转换TCP/UDP 连接中常用的 socket 接口套接字 什么是套接字&#xff1f; 所谓 套接字 (Socket) &#xff0c;就是对网络中 不同主机 上的应用进程之间进行双向通信的端点的抽象。 UNIX/L…

网络协议分析 | 传输层 :史上最全UDP、TCP协议详解,一篇通~

文章目录UDP概念格式UDP如何实现可靠传输基于UDP的应用层知名协议TCP概念格式保证TCP可靠性的八种机制确认应答、延时应答与捎带应答超时重传滑动窗口滑动窗口协议后退n协议选择重传协议流量控制拥塞控制发送窗口、接收窗口、拥塞窗口快速重传和快速恢复连接管理机制三次握手连…

JDom,jdom解析xml文件

1.要解析的文件模板如下&#xff1a; <?xml version"1.0" encoding"GBK"?> <crsc> <data><举报信息反馈><R index"1"><举报编号>1</举报编号><状态>1</状态><答复意见>填写…

网络协议分析 | 应用层:HTTP协议详解、HTTP代理服务器

文章目录概念URLHTTP协议的特点HTTP协议版本格式请求报文首行头部空行正文响应报文首行头部空行正文Cookie与SessionHTTP代理服务器正向代理服务器反向代理服务器透明代理服务器概念 先了解一下 因特网&#xff08;Internet&#xff09; 与 万维网&#xff08;World Wide Web&…