【剑指 2】面试题 43:1~n 整数中 1 出现的次数

题目:输入一个整数 n,求 1~n 这 n 个整数的十进制表示中 1 出现的次数。例如,输入 12,1~12 这些整数中包含 1 的数字有 1、10、11 和 12,1 一共出现了 5 此。

对于 X ∈ [1, 9],1~n 整数中 X 出现的次数在算法一样。(0 的比较特殊,不过大致思想类似)。


解题思路:

分别以 12493、12593、12693 为例,计算数字 5 出现的次数。

其中,结果为 5 分别在个位、十位,直到万位出现的次数的和。

以 5 在百位上出现的次数为例进行讲解:

  1. 对于 12493,百位上位为 4 < 5,所以其更高位,即万、千位只能从 00 - 11 进行变换,即 01、02...10、11 进行变化,共 12 种;而其更低位,即十、个位只能从 00 - 99 进行变换(因为万千位最大也才 11,即 115XX,此时十个位最大可为 99,即 11599,小于 12493),共 100 种。

    因此,对于 12493,5 在百位出现的次数位 12 * 100 = 1200

  2. 对于 12593,百位上为 5 == 5。所以其更高位,即万、千位只能从 00 - 12 进行变换;而其更低位,就需要看情况了:
    (1)当万千位为 00 - 11 的时候,百十位可以是 00 - 99 进行变换;
    (2)当万千位为 12 的时候,因为不能大过 12593,因此只能从 00 - 93 进行变换,共 94 种。

    因此,对于 12493,5 在百位出现的次数位 12 * 100 + 94 = 1294

  3. 对于 12693,百位上为 6 > 5。所以其更高位,即万、千位能从 00 - 12 进行变换,共 13 种;而其更低位,即十、个位能从 00 - 99 进行变换(因为万千位最大也才 12,即 125XX,此时十个位最大可为 99,即 12599,小于 12693),共 100 种。

    因此,对于 12693,5 在百位出现的次数位 13 * 100 = 1300

对于 5 在其他位上出现的次数,也类似。


算法的具体实现:
// 用于控制数字 X 出现的次数
private static int X = 1;

public int NumberOf1Between1AndN_Solution(int n) {
    if (n < 1) return 0;
    if (n < 10) return 1;
    int sum = 0;
    // 用于辅助判断是不是把 n 的每一位遍历完了
    int tag = n;
    // 用于记录位的索引,从 n 的个位向高位开始
    int index = 1;
    while (tag > 0) {
        int mi = (int) Math.pow(10, index);
        int num = n % mi;
        // 得到当前位的更高位
        int high = n / mi;
        int mi2 = (mi / 10);
        // 得到当前位
        int cur = num / mi2;
        // 得到当前位的更地位
        int low = num % mi2;
        // 记录当前位出现 X 的次数
        int count = 0;
        if (cur < X) {
            count = high * mi2;
        } else if (cur > X) {
            count = (high + 1) * mi2;
        } else {
            count = high * mi2 + (low + 1);
        }
        tag /= 10;
        ++index;
        System.out.println(count);
        sum += count;
    }
    return sum;
}

一个数 n 有 ((O(log10 n) 取整) + 1) 位,因此上述算法的时间复杂度为 O(log10 n )。

为什么数 n 有 ((O(log10 n) 取整) + 1) 位?

因为假设 n ∈ [10x, 10x+1-1],且 n 为整数,则 n 对于的位数属于 x + 1。例如 199,其属于 [100, 999],有 log10 100 = 2,则 199 对应的位数为 2 + 1 = 3.


参考文章:剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值