面试题43:1~n整数中1出现的次数(有比剑指Offer更好懂的算法)

面试题43:1~n整数中1出现的次数

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

思路1:遍历n个数,统计每个数中1出现的次数,时间复杂度O(nlogn),此方法不是最优

//思路1
int number1Between1AndNMethod1(int n)
{
    if (n < 0)
        return -1;

    int numbers = 0;
    for (int i = 0; i <= n; i++)
    {
        numbers += number1OfN(i);
    }
    return numbers;
}
//计算每个数字中1的个数
int number1OfN(int n)
{
    int numbers = 0;
    while (n > 0)
    {
        if (n % 10 == 1)
        {
            numbers++;
        }
        n = n / 10;
    }
    return numbers;
}

思路2:假想数字中的每一位是一个转筒

  • 设数字n的为1456,为了计算从1到n这个n个数中1出现的次数,假想这四个数字是一个转筒,每一个位置每转一圈出现1次数为其权重,个位的权重为1,十位的权重为10.……;
    -数字0000转到1456,对于个位6而言,要达到1456,需要转145圈,得到1450,由于6大于1,还需要转过1,所以总共转(145+1)= 146圈;
  • 对于十位5,要达到1456,需要转14圈,1400,由于5大于1,还需要转过1,所以总共转(14+1)= 15圈;
  • 对于百位4,要达到1456,需要转1圈,1000,由于4大于1,还需要转过1,所以总共转(1+1)= 2圈;
  • 对于千位1,没有高位,转不了一圈,同时本身为1,也转不过1(转过1表示由1变为2),所以千位上出现1的次数为低位加1,即(456+1)= 457;其他位为1的类似

每位出现1的次数位:圈数*权重+由于本身为1时存在的次数,然后计算这些位出现的次数总和,时间复杂度位O(logn)。

//思路2
int number1Between1AndNMethod2(int n)
{
    if (n < 0)
        return -1;
    int weight = 1;
    int numbers = 0;

    int high = n;
    while (high > 0)
    {
        //高位
        high = n / (weight * 10);
        //低位
        int low = n % weight;
        //当前位
        int bit = ((n - low) / weight) % 10;
        if (bit > 1)
        {
            numbers += (high + 1) * weight;
        }
        else if (bit == 1)
        {
            numbers += high * weight + low + 1;
        }
        weight *= 10;
    }
    return numbers;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值