1. 题目
给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
示例 1:
输入:n = 13
输出:6
示例 2:
输入:n = 0
输出:0
提示:
- 0 <= n <= 1 0 9 10^9 109
2. 分析
看 n n n的范围,力扣的数字上限是 2 × 1 0 9 2\times 10^9 2×109,所以时间复杂度必须是 O ( n ) O(n) O(n),这意味着必须一遍遍历完成所有的计算,或者找出与 n n n相关的公式,只计算一次。当前,力扣的经典思路为公式法:
- 所有 ≤ n \leq n ≤n的数字中,个位1的个数
1 | 1 |
---|---|
2 | 1 |
3 | 1 |
… | 1 |
11 | 2 |
… | 2 |
21 | 3 |
… | 3 |
41 | 4 |
… | 4 |
n | ⌊ n 10 ⌋ + m i n ( n mod 10 , 1 ) \lfloor\frac{n}{10}\rfloor+min(n \textbf{mod} 10,1) ⌊10n⌋+min(nmod10,1) |
对于公式 n 10 + m i n ( n mod 10 , 1 ) \frac{n}{10}+min(n \textbf{mod} 10,1) 10n+min(nmod10,1),其实它的意思是如果 n mod 10 n \textbf{mod} 10 nmod10 大于等于1,则 m i n ( n mod 10 , 1 ) min(n \textbf{mod} 10,1) min(nmod10,1)取1,如果 n mod 10 n \textbf{mod} 10 nmod10为0,则 m i n ( n mod 10 , 1 ) min(n \textbf{mod} 10,1) min(nmod10,1)取0.
所有 ≤ n \leq n ≤n的数字中,十位1的个数
1 | 0 |
---|---|
… | 0 |
10 | 1 |
11 | 2 |
12 | 3 |
… | … |
20 | 10 |
21 | 10 |
… | 10 |
110 | 11 |
111 | 12 |
112 | 13 |
… | … |
120 | 20 |
120 | 20 |
… | … |
n | ⌊ n 100 ⌋ × 10 + m i n ( m a x ( n mod 100 − 10 + 1 , 0 ) , 10 ) \lfloor\frac{n}{100}\rfloor\times 10 + min(max(n\textbf{mod}100-10+1,0),10) ⌊100n⌋×10+min(max(nmod100−10+1,0),10) |
对于公式 ⌊ n 100 ⌋ × 10 + m i n ( m a x ( n mod 100 − 10 + 1 , 0 ) , 10 ) \lfloor\frac{n}{100}\rfloor\times 10 + min(max(n\textbf{mod}100-10+1,0),10) ⌊100n⌋×10+min(max(nmod100−10+1,0),10),其实它的意思是首先可以肯定一个大于100的数,每整百肯定有10个数字的十位数为1,对于不到整百的数,则需要另外处理。以数字152为例,其前100个数字里面,10-19这10个数字的十位数为1,之后还剩数字101-152没有计数。101-152最多可以产生10个符合要求的数字110-119,则有 m i n ( X , 10 ) min(X,10) min(X,10)。
再推断 X X X的部分,以数字112为例,其前100个数字里面,10-19这10个数字的十位数为1,之后还剩数字101-112没有计数。具体考虑,前9个数字101-109肯定不符合,还剩3个数字,110-112,它们刚好符合,则有 n mod 100 − ( 10 − 1 ) n\textbf{mod}100-(10-1) nmod100−(10−1)。为了防止这部分公式变为0,加一个限制,则有 m a x ( n mod 100 − 10 + 1 , 0 ) max(n\textbf{mod}100-10+1,0) max(nmod100−10+1,0).
之后对百位推理,则有 ⌊ n 1000 ⌋ × 100 + m i n ( m a x ( n mod 1000 − 100 + 1 , 0 ) , 100 ) \lfloor\frac{n}{1000}\rfloor\times 100 + min(max(n\textbf{mod}1000-100+1,0),100) ⌊1000n⌋×100+min(max(nmod1000−100+1,0),100)
对倒数第k位推理,则有 ⌊ n 1 0 k + 1 ⌋ × 1 0 k + m i n ( m a x ( n mod 1 0 k + 1 − 1 0 k + 1 , 0 ) , 1 0 k ) \lfloor\frac{n}{10^{k+1}}\rfloor\times {10^k} + min(max(n\textbf{mod}10^{k+1}-10^k+1,0),10^k) ⌊10k+1n⌋×10k+min(max(nmod10k+1−10k+1,0),10k)
3. 代码实现
class Solution {
public int countDigitOne(int n) {
long mulk = 1;//10^k
int ans = 0;
for (int k = 0; n >= mulk; ++k) {
ans += (n / (mulk * 10)) * mulk + Math.min(Math.max(n % (mulk * 10) - mulk + 1,0), mulk);
mulk *= 10;
}
return ans;
}
}