【LeetCode-数学】1~n整数中1出现的次数

题目描述

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

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

示例:

输入:n = 12
输出:5

输入:n = 13
输出:6

说明:
1 <= n < 2^31
题目链接: https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/

思路

由于 n 的范围非常大,所以暴力求解是行不通的。

假设 n 是 x 位数,第 i 位表示为 \(n_i\),所以 \(n=n_xn_{x-1}\dots n_1\)。我们从第 i 位 \(n_i\) 将 n 分为两个部分:

  • \(n_xn_{x-1}\dots n_{i+1}\) 被称为高位 high;
  • \(n_{i-1}n_{i-2}\dots n_1\) 被称为地位 low;
  • \(n_i\) 被称为当前位 cur;
  • \(10^i\) 称为位因子,记为 digit;

high、low、cur、digit 的初始化为:

int high = n/10;
int low = 0;
int cur = n%10;
long digit = 1; // long 类型,否则会溢出

high、low、cur、digit 的更新方法为:

low += cur*digit;
cur = high%10;
high /= 10;
digit *= 10;

在每一步,我们根据 high、low、cur、digit 的情况来计算 1 的个数 ans,具体分 3 种情况:

  • cur==0,此时 ans += high*digit;
  • cur==1,此时 ans += hight*digit+low+1;
  • cur==2~9 的情况,ans += (high+)*digit;

这篇题解举了几个例子来介绍为什么要这么做。

代码如下:

class Solution {
public:
    int countDigitOne(int n) {
        int high = n/10;
        int low = 0;
        int cur = n%10;
        long digit = 1;  // long 类型,否则会溢出
        int ans = 0;
        while(high!=0 || cur!=0){  // 注意条件
            if(cur==0) ans += high*digit;
            else if(cur==1) ans += high*digit+low+1;
            else ans += (high+1)*digit;

            low += cur*digit;
            cur = high%10;
            high /= 10;
            digit *= 10;
        }
        return ans;
    }
};
  • 时间复杂度:O(logn)
  • 空间复杂度:O(1)

参考

https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/

posted @ 2020-07-25 22:10  Flix  阅读(262)  评论(0编辑  收藏  举报