题目

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

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

示例

  • 示例1

输入:n = 12
输出:5

  • 示例2

输入:n = 13
输出:6

解题思路

将 11 ~ nn 的个位、十位、百位、…的 11 出现次数相加,即为 11 出现的总次数。

这边可以使用排列组合的方法解决,统计所有1出现的次数,我们可以吧所有整数理解为行李箱上的密码锁,先固定某一位上的数据控制为1,然后归纳所有数字的出现的次数。

我们假设 n = 13 (用个小点的数,比较容易举例)

我们需要统计小于等于 13 的数中,出现 1 的次数,

通过上图可知,个位上 1 出现 2 次,十位上 1 出现 4 次,

那么总次数为 2 + 4 = 6 次。

另外我们发现 11 这个数,会被统计 2 次,它的十位和个位都为 1 ,
而我们这个题目是要统计 1 出现的次数,而不是统计包含 1 的整数,所以上诉方法不会出现重复统计的情况。

我们题目已经有大概思路啦,下面的难点就是如何统计每一位中 1 出现的次数呢?

我们完全可以通过遍历 n 的每一位来得到总个数,见下图:

假设我们想要得到十位上 1 出现的次数,当前我们指针指向十位,

我们称之为当前位。num 则代表当前位的位因子,当前位为个位num = 1十位时为 10,百位时为 100…

那我们将当前位左边的定义为高位当前位右边的定义位低位

例:n = 1004 ,此时指针指向十位(当前位)num = 10,高位为百位,千位,低位为个位

而且我们某一位的取值范围为 0 ~ 9,那么我们可以将这 10 个数分为 3 类小于 1 (当前位数字为 0 ),等于 1(当前位数字为 1 ) ,大于 1(当前位上数字为 2 ~ 9),下面我们就来分别考虑三种情况。

我们进行举例的 n 为 1004,1014,1024。重点讨论十位上 3 种不同情况。大家阅读下方文字之前,先想象自己脑子里有一个行李箱的滚轮密码锁,我们固定其中的某一位,然后可以随意滑动其他位,这样可以帮助大家理解。

n = 1004
我们想要计算出小于等于 1004 的非负整数中,十位上出现 1 的次数。

也就是当前位为十位,数字为 0 时,十位上出现 1 的次数

解析:为什么我们可以直接通过高位数字 * num,得到 1 出现的次数
因为我们高位为 10,可变范围为 0 ~ 10,但是我们的十位为 0 ,所以高位为 10 的情况取不到,所以共有 10 种情况。
又当前位为十位,低位共有 1 位,可选范围为 0 ~ 9 共有 10 种情况,所以直接可以通过 10 * 10 得到。

其实不难理解,我们可以设想成行李箱的密码盘,在一定范围内,也就是上面的 0010 ~ 0919固定住一位为 1 ,只能移动其他位,看共有多少种组合。

好啦,这个情况我们已经搞明白啦,下面我们看另一种情况。

n = 1014

我们想要计算出小于等于 1014 的非负整数中,十位上出现 1 的次数。

也就是当前位为十位数字为 1 时,十位上出现 1 的次数

我们在小于 1014 的非负整数中,十位上为 1 的最小数字为 10最大数字为 1014,所以我们需要在 10 ~ 1014 这个范围内固定住十位上的 1 ,移动其他位。

其实然后我们可以将 1014 看成是 1004 + 10 = 1014

则可以将 10 ~ 1014 拆分为两部分 0010 ~ 0919 (小于 1004 ),1010 ~ 1014。

见下图

解析:为什么我们可以直接通过 高位数字 * num + 低位数字 + 1 即 10 * 10 + 4 + 1
得到 1 出现的次数
高位数字 * num 是得到第一段的次数,第二段为 低位数字 + 1,求第二段时我们高位数字和当前位已经固定,
我们可以改变的只有低位。
可以继续想到密码盘,求第二段时,把前 3 位固定,只能改变最后一位。最后一位最大能到 4 ,那么共有几种情况?

n = 1024

我们想要计算出小于等于 1024 的非负整数中,十位上出现 1 的次数。

也就是当前位为十位,数字为 2 ~ 9 时,十位上出现 1 的次数。其中最小的为 0010,最大的为 1019

我们也可以将其拆成两段 0010 ~ 0919,1010 ~ 1019

可以继续想到密码盘,求第二段时,把前 3 位固定,只能改变最后一位。最后一位最大能到 4 ,那么共有几种情况?

n = 1024

我们想要计算出小于等于 1024 的非负整数中,十位上出现 1 的次数。

也就是当前位为十位,数字为 2 ~ 9 时,十位上出现 1 的次数。其中最小的为 0010,最大的为 1019

我们也可以将其拆成两段 0010 ~ 0919,1010 ~ 1019

解析:为什么我们可以直接通过高位数字 * num + num, 10 * 10 + 10 得到 1 出现的次数
第一段和之前所说一样,第二段的次数,我们此时已经固定了高位和当前位,当前位为 1,低位可以随意取值,上诉例子中,当前位为 10,低位为位数为 1,则可以取值 0 ~ 9 的任何数,则共有 10 (num) 种可能。

好啦,这个题目大家应该理解的差不多啦。

算法实现

/*** @param {number} n* @return {number}*/
var countDigitOne = function(n) {//高位var high = n;//低位var low = 0;//当前位var cur = 0;var count = 0;var num = 1;while (high != 0 || cur != 0) {cur = high % 10;high = Math.floor(high/10) ;//这里我们可以提出 high * num 因为我们发现无论为几,都含有它 if (cur == 0) count += high * num;else if (cur == 1) count += high * num + 1 + low; else count += (high + 1) * num;//低位low = cur * num + low;                  num *= 10;}return count;};
注意事项

这边需要注意的是,在对高位high除10取整时一定要注意使用Math.floor()函数——向下取整,JS除法在运算中不会对除法四舍五入,所以这边一定要注意数据的准确性和一致性。如果不加Math.floor()这个方法,最后得出的结果是NAN

【leecode 剑指offer】 1~n整数中1出现的次数相关推荐

  1. 【剑指offer】_11整数中1出现的次数

    题目描述 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了. ...

  2. 【算法】剑指 Offer 56 - II. 数组中数字出现的次数 II 【重刷】

    1.概述 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次.请找出那个只出现一次的数字. 示例 1: 输入:nums = [3,4,3,3] 输出:4 示例 2: 输入:nums ...

  3. 2021-09-04剑指Offer43.1~n整数中1出现的次数

    暴力解法,超过时预定 class Solution {public:int countDigitOne(int n) {int counter = 0;for(int i = 1;i <= n; ...

  4. leetcode:剑指 Offer 56 - I. 数组中数字出现的次数

    故心故心故心故心小故冲啊 文章目录 题目 一.解法一:set(利用不重复特性) 二.解法二:lowbit(x)位运算 题目 一.解法一:set(利用不重复特性) /*** @param {number ...

  5. 剑指offer 56 - 1.数组中数字出现的次数

    一个整型数组 nums 里除两个数字之外,其他数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 示例 1: 输入:nums = [4,1,4,6] ...

  6. 【算法】剑指 Offer 56 - I. 数组中数字出现的次数 【重刷】太难了

    1.概述 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 示例 1: 输入:nums = [4,1 ...

  7. 剑指offer II 001.整数除法

    剑指 Offer II 001. 整数除法 整数除法 题目链接 题目要求: 给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 '*'.除号 '/' 以及求余符号 '%' . 注 ...

  8. 剑指 Offer II 014. 字符串中的变位词

    剑指 Offer II 014. 字符串中的变位词 题目 示例 解答 题目来源为leetcode 题目 给定两个字符串s1和s2,写一个函数来判断s2是否包含s1的某个变位词. 换句话说,第一个字符串 ...

  9. 【LeetCode】剑指 Offer 44. 数字序列中某一位的数字

    [LeetCode]剑指 Offer 44. 数字序列中某一位的数字 文章目录 [LeetCode]剑指 Offer 44. 数字序列中某一位的数字 package offer;public clas ...

  10. 【剑指offer】_18 数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值.我们 ...

最新文章

  1. linux lab命令,Linux lab 命令
  2. Entity Framework 的事务 DbTransaction
  3. python contains_Python中有判断字符串包含(contains)子串的方法吗?
  4. WinForm登录模块设计开发
  5. pom.xml中的dependency标签的classifier
  6. 表达式 jsp_[JSTL表达式] -JSTL中的所有,都在这
  7. 高温保护_耐高温保护膜可以用在哪一方面?
  8. Angular2开发拙见——组件规划篇
  9. Java记录 -59- SortedSet
  10. 【java】照片查看器:开发一个简易照片查看器,自行设计功能和界面。
  11. 耳机频谱曲线测试软件,通过耳机频响曲线来调EQ,免费的音质提升你要吗?
  12. 服务器安装julia_julia | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror...
  13. aliddns ipv6_IPv6 + aliddns 实现群晖外网控制
  14. VSCode远程控制服务器
  15. AE的QuickTime问题
  16. 京东、搜狗“带狗”都好好的,为何司机对快狗打车不满意?
  17. cesium 直接加载 geotiff 影像图
  18. 小技巧:如何在R语言与excel/word之间进行复制粘贴
  19. glib 交叉编译记录
  20. 苹果蓝牙日志如何获取

热门文章

  1. c语言编程之美输入二叉树,八方体育网址多少-官网首页
  2. Tomcat 访问Manager APP报403错误
  3. 基于STM32的倾斜仪设计(一)—— 硬件设计(1)
  4. Redis常用命令|查询|删除|模糊操作
  5. 相比人类,机器人护理更加让老人没负担?
  6. python modbus-tk 实现三菱FX5U modbus-tcp 从站通讯
  7. 每天起床第一句,先给自己打个气
  8. PHPStudy安装espcms
  9. UI - 怎么用PS设计出艺术字体的样式
  10. Linux C 格式化SD卡