leetcode 233 数字1的个数

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的个数
11
21
31
1
112
2
213
3
414
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的个数

10
0
101
112
123
2010
2110
10
11011
11112
11213
12020
12020
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(nmod10010+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(nmod10010+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(101)。为了防止这部分公式变为0,加一个限制,则有 m a x ( n mod 100 − 10 + 1 , 0 ) max(n\textbf{mod}100-10+1,0) max(nmod10010+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(nmod1000100+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+110k+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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古承风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值