剑指offer_43_1~n整数中1出现的次数【javascript】

73 阅读3分钟

题目链接

leetcode.cn/problems/1n…

题目

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。 例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

示例 1:

输入:n = 12
输出:5

示例 2

输入:n = 13
输出:6

限制:

题解

数字规律

  • 时间复杂度 O(log⁡n) : 循环内的计算操作使用 O(1) 时间;循环次数为数字 n 的位数,即 log⁡n,因此循环使用 O(log⁡n)时间。
  • 空间复杂度 O(1) : 几个变量使用常数大小的额外空间。

链接:leetcode.cn/problems/nu…

将 1 ~ n 的个位、十位、百位、...的 1 出现次数相加,即为 1 出现的总次数。

高位 ,记为 high。当前位记为 cur。低位记为 low; 将 「10^i」称为 位因子 ,记为 digit 。 根据当前位 cur 值的不同,分为以下三种情况:

  • 当 cur=0 时: 此位 1 的出现次数只由高位 high 决定,计算公式为:high×digit; 以 n=2304 为例,求 digit = 10(即十位)的 1 出现次数。数字划分为三部分,高位23,cur0,低位4出现1的数字范围0010-2219,只看高、低位为000-229,计算为:229 - 0 + 1 = 230,所以结果为23×10=230。

  • 当 cur=1 时: 此位 1 的出现次数由高位 high 和低位 low 决定,计算公式为:high × digit + low + 1; 以 n=2314 为例,求 digit=10(即十位)的 1 出现次数。出现1的数字范围0010-2314,只看高、低位为000-234,计算为:234 - 0 + 1 = 235,所以结果为23 × 10 + 4 + 1 = 235。

  • 当 cur>1 时: 此位 1 的出现次数由高位 high 决定,计算公式为:(high+1)×digit; 以 n=2324 为例,求 digit=10(即十位)的 1 出现次数。出现1的数字范围0010-2319,只看高、低位为000-239,计算为:239 - 0 + 1 = 240,所以结果为(23 + 1) × 10 = 240。

/**
 * @param {number} n
 * @return {number}
 */
var digitOneInNumber = function(n) {
    let res = 0;

    let high = Math.floor(n / 10), 
    cur = n % 10, 
    low = 0, 
    digit = 1;

    while(high != 0 || cur != 0) {
        if (cur == 0) res += high * digit;
        else if (cur == 1) res += high * digit + low + 1;
        else res += (high + 1) * digit;
        low += cur * digit
        cur = high % 10
        high = Math.floor(high / 10)
        digit *= 10
    }
    return res
};

枚举每一数位上 1 的个数

  • 时间复杂度:O(log⁡n)。n 包含的数位个数与 n 呈对数关系。
  • 空间复杂度:O(1)。
/**
 * @param {number} n
 * @return {number}
 */
var countDigitOne = function(n) {
    // mulk 表示 10^k
    // 在下面的代码中,可以发现 k 并没有被直接使用到(都是使用 10^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;
};

累加

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)
/**
 * @param {number} n
 * @return {number}
 */
var countDigitOne = function(n) {
    let number = 0;
    for(let i = 1; i <= n; i++) {
        number += numberOf1(i);
    }
    return number;
};
var numberOf1 = (n) => {
    let number = 0;
    while(n) {
        if (n % 10 === 1) {
            number++;
        }
        n = parseInt(n / 10);
    }
    return number;
}