题目描述
输入一个整数 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/