【剑指offer】1~n 整数中 1 出现的次数

这篇博客解析了一道数学难题,即计算1到n之间整数表示中1出现的次数。通过从数位角度分析问题,将数字分为高位、当前位和低位,并举例说明了不同情况下1出现的计数方式。最后给出了O(logn)时间复杂度的解决方案,并附带了具体代码实现。
摘要由CSDN通过智能技术生成
🔥题目

输入一个整数n,求1~n这n个整数的十进制表示中1出现的次数。

输入:12
输出:5
解释:1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

 

☘️解析

这是一道比较困难的数学题。下面将用几个具体的例子,带大家弄明白代码思路。

我们不按照数字递增(1,2,3,4,5,…,1024,1025,…)的角度去考虑问题,而是从数位(个位、十位、百位、千位…)的角度去考虑问题。

我们将某一位的数字固定为1,然后去计算其他位所有可以取到的情况——想象一下,这里有一个密码箱,其中一位被固定,我们来拨动其他位的滚轮,但不能让数字小于当前数组,计数可以取到多少种情况。每个位置都固定一次1后,所有情况的总和即为最终答案。

接下来,我们把这个密码箱上数字,划分为三个区域(以数字45678为例):

1)当前位数字 cur(假设此时固定百位,即6)
2)高位数字 hi(即45)
3)低位数字 lo(即78)

并设置两个变量:

4)位数 digit(即100)
5)计数 count(全局累加)

明确了这些规定,下面我们用三个例子(一共会出现三种情况)计算一下。下面的三个例子,都假设此时计算到十位、高位为10、低位为4。
 
1004

十位拨到1并固定,变为1014。
高位可以取0~9,低位可以取0~9,计数加上 hi * digit = 10 * 10 = 100

1014

十位拨到1并固定,本来就是1014。
高位可以取0~9,低位可以取0~4,计数加上 hi * digit + (lo + 1) = 10 * 10 + 5= 105

1024

十位拨到1并固定,变为1014。
高位可以取0~10,低位可以取0~9,计数加上 (hi + 1) * digit = 11 * 10 = 110

1034、1044、1054、1064、1074、1084、1094

同1024
 

根据这三个例子,很容易写出下面的代码!

 

🧊代码
class Solution {
    public int countDigitOne(int n) {
        int count = 0;      // 计数
        int digit = 1;      // 位数
        int lo = 0;         // 低位数字
        int hi = n;         // 高位数字
        int cur = 0;        // 当前位数字
        while (hi != 0 || cur != 0) {
            cur = hi % 10;
            hi /= 10;
            if (cur == 0) {
                count += (hi * digit);
            } else if (cur == 1) {
                count += (hi * digit + (lo + 1));
            } else {
                count += ((hi + 1) * digit);
            }
            lo = cur * digit + lo;
            digit *= 10;
        }
        return count;
    }
}

 

🌸补充

时间复杂度:O(logn)

解释:算法是按位进行遍历的,假如n=999,则循环了3次。有意思的是,这里的logn是以10为底数的,平常我们说的logn都是以2为底数的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值