剑指offer-31:整数中1出现的次数(从1到n整数中1出现的次数)

参考: https://troywu0.gitbooks.io/interview/整数中出现1的次数(从1到n整数中1出现的次数).html

题目描述

求出1 ~ 13的整数中1出现的次数,并算出100 ~ 1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

解题思路1 (暴力法,时间复杂度: O(nlog(n))

这种方法的思路简单,统计每一个数中出现1的次数,能够快速写出代码。但是,这种方法的时间复杂度很高,O(nlog(n)),面试这么写,估计不会留下好的印象。

public int NumberOf1Between1AndN_Solution(int n) {
    int count = 0;
    while (n > 0) {
        String nStr = String.valueOf(n);
        for (int i = 0; i < nStr.length(); i++) {
            if (nStr.charAt(i) == '1')
                count++;
        }
        n--;
    }
    return count;
}

解题思路2 (数学规律法,时间复杂度: O(log(n))

public int NumberOf1Between1AndN_Solution(int n) {
    int low = 0, cur = 0, high = 0;
    int count = 0;
    int factor = 1;
    while (factor <= n) {
        high = n / (factor * 10);
        low = n % factor;
//            cur = (n - high * (factor * 10) - low) / factor;
        cur = (n / factor) % 10;
        if (cur == 0)
            count += high * factor;
        else if (cur == 1)
            count += high * factor + low + 1;
        else
            count += (high + 1) * factor;
        factor *= 10;
    }
    return count;
}

这一个思路利用了数字的规律和特点,解决问题的效率非常的高,时间复杂度只与数的位数有关。

首先看一个规律:

  • 从1 - 10中,个位中 1 出现的次数是1,即1这个数;
  • 从1 - 100中,十位中 1 出现的次数是10, 即10, 11, …, 18, 19;
  • 从1 - 1000中,百位中 1 出现的次数是100,即100, 101, …, 198, 199;
  • 以此类推。

假设有一个四位数,使用 cur 来表示当前位数对应的数值,high表述cur左边的数,low表示cur右边的数。会有三种情况产生:

  • 第一种:cur = 0,1出现的次数等于 high * (该位数对应的基数)
    • 假设四位数为1023,求百位上1出现的次数;
    • 此时 high = 1, cur = 0, low = 23;
    • 次数 = 1 * 100;
    • 即100, 101, …, 198, 199。
  • 第二种:cur = 1,1出现的次数等于 high * (该位数对应的基数) + low + 1
    • 假设四位数为1123,求百位上1出现的次数;
    • 此时 high = 1, cur = 1, low = 23;
    • 次数 = 1 * 100 + 23 + 1;
    • 即100, 101, …, 198, 199 + 1100, 1101, …, 1122, 1123。
  • 第三种:cur > 1,1出现的次数等于 (high + 1) * (该位数对应的基数)
    • 假设四位数为1223,求百位上1出现的次数;
    • 此时 high = 1, cur = 2, low = 23;
    • 次数 = (1 + 1) * 100;
    • 即100, 101, …, 198, 199 + 1100, 1101, …, 1198, 1199。

根据这一规律,从最低位至最高位,依次求出1出现的次数,最后相加得到最终的结果。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值