LeetCode打卡day9

131 阅读2分钟

“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”

一、题目描述:

1~n 整数中 1 出现的次数

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

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

示例 1:

输入:n = 12 输出:5

示例 2:

输入:n = 13 输出:6  

限制:

1 <= n < 2^31

二、思路分析:

对于一个数n,

  1. 假设他是一位整数,则一出现的次数为0或者1:当n<1时即n为0时1出现次数为0;其他1出现次数为1

    • 假设是两位整数n1 n0,则对于其个位数上的分析就是第一种情况,而因为存在十位n1,故个位上1的情况出现了n1* 1次,例如20,01,11,故若存在十位则个位上的1的数量为n1 * 1+个位数值<1?0:1;
    • 对于十位上的分析如下,因为十位存在不可能为0,9>=n1>=1,对2位数来说只要n1n0>=20十位数上1的数量肯定有10次,10~ 19;而当n1=1时出现次数与个位上的数有关 n0+1 例如12十位数上出现1位10,11,12,即12-10+1;而我们的n1 n0可能作为三位数或者多位数的中间组成部分,这是n1肯为0,明显为0不可能有1出现在十位上
    • 假设三位数n2 n1 n0,分析个位数上结果结合1,2两种情况,同时加上对百位数的分析即加上n2* 10;
    • 而对于十位数,因为百位数存在了,新增了n2* 10个十位数为1的情况,例如对于 231,有110~ 119,010~019,再加上第二种情况对其分析
    • 对于百位数,同样的若n3》=2肯定有100个位1情况100~199,小于1肯定为0,等于1情况看n2n1n0-100+1

    从上面情况可以得出对于第k位数,k=0,1,2……k-1对于个十百千位,其出现1的次数与前面和后面的位数有密切关系,可以通过image.png获取k位后的位数nk+1……nk-1,在* 代表的10^k次方获得高位对其的影响;

而对于后面的使用取模获得n mod 10^(k+1),使用(n mod 10^(k+1))-10^k +1次方,但是结果可能未负数或者大于10^k次方,我们希望小于0时为0,大于10^k次方时就为10^k次方。故一下为公式

image.png

三、AC代码

var countDigitOne = function(n) {
    // mulk 表示 10^k
    // 在下面的代码中,可以发现 k 并没有被直接使用到
    // 但这里保留了 k为了让代码看出当前位数
    let mulk = 1;
    let ans = 0;
    for (let k = 0; n >= mulk; ++k) {
        ans += (Math.floor(n / (mulk * 10))) * mulk + Math.min(Math.max(n % (mulk * 10) - mulk + 1, 0), mulk);
        mulk *= 10;
    }
    return ans;
};

四、总结

本题纯粹看数学知识,要通过多些几个例子来找出各个位数间的关系,通过写出公式