1~n 中整数1出现的次数

剑指 Offer 43 | 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 < 231

思路:都是统计1 ~ n中各个位上1出现的次数然后相加,个位上1出现的次数 + 十位上1出现的次数 + 百位上1出现的次数+ … 。

方法一:
计算每个位数上1出现的次数时,先计算 [ 0 , n / 10 − 1 ] [0, n / 10 - 1] [0,n/101] 中1出现的次数,再计算 [ n / 10 , n ] [n / 10, n] [n/10,n] 中1出现的次数。因为 [ 0 , n / 10 − 1 ] [0, n / 10 - 1] [0,n/101]中1出现的次数是有规律的:
个位上1出现的次数:
[0, 9] 1次
[0, 99] 10次
[0, 999] 100次
[0, 9999] 1000次
十位上1出现的次数:
[0, 99] 10次
[0, 999] 100次
[0, 9999] 1000次

所以当 cur = 0 时, 只需要计算 [ 0 , n / 10 − 1 ] [0, n / 10 - 1] [0,n/101] 中 cur 位上1出现的次数 (这里的 n 是指最开始传入的 n;下面的代码中 n 每次循环都要除10,不是原始的 n 了)
当 cur = 1 时, 还要计算 [ n / 10 , n ] [n / 10, n] [n/10,n] 中1出现的次数为 low + 1;
当 cur > 1 时, [ n / 10 , n ] [n / 10, n] [n/10,n] 中1出现的次数刚好为 num;

int countDigitOne(int n) {
    //高位
    int low = 0, count = 0, cur;
    long num = 1; // 表示个位、十位、百位
    while (n != 0) {
        cur = n % 10; // 从个位开始遍历
        n /= 10; //
        count += n * num;
        if (cur == 1) count += low + 1;
        else if (cur > 1) count += num; 
        low += cur * num; // 记录遍历过的位数上的值,当 cur = 1 时,可以组成的 cur 位上为1的数有 low + 1 个。                  
        num *= 10;
    }
    return count;
}

方法二:
理解起来和方法一类似,只是求当 cur >= 1 时,计算 [ n / 10 , n ] [n / 10, n] [n/10,n] 的部分1出现的次数的方式不同
大佬总结出来的数学公式:
n 1 0 k + 1 {n} \over {10^{k+1} } 10k+1n × 1 0 k \times 10^k ×10k + min ( max ( n mod 10k+1 - 10k +1, 0), 10k)
k=0,1,2 分别表示个位、十位、百位…

int countDigitOne(int n) {
    long long num = 1;
    int count = 0;
    while (n >= num) {
        count += (n / (num * 10)) * num; // 注意:n / (num * 10) * num 不等于 n / 10
        count += min(max(n % (num * 10) - num + 1, 0LL), num); // n % (num * 10) - num 为方法一中的low
        num *= 10;
    }
    return count;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值