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

本文探讨了计算1到n范围内数字1出现总次数的三种算法思路,包括暴力破解、逐个数字计数及利用数字规律的高效算法,并详细解析了每种方法的实现细节与复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

考察点:数学思维,发散思维。

思路1:参考讨论区,暴力破解。把所有数字转成字符串,再进行字符串单个查找,复杂度较高但是可行。

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        int count = 0;
        string s;
        for (int i = 1; i <= n; i++)
            s += to_string(i);
        for (int i = 0; i < s.size(); i++)
            if (s[i] == '1')
                count++;
        return count;
    }
};

思路2:分别判断一个数字有多少个1,进行循环累加。复杂度为O(nlogn) 复杂度较高。

class Solution {
public:
    int numOf1(unsigned int num)//计算一个数字里面含有几位1,分位判断
    {
        int number = 0;
        while (num)
        {
            if (num % 10 == 1)
                number++;
            num = num / 10;
        }
        return number;
    }
    int NumberOf1Between1AndN_Solution(int n)
    {
        int count = 0;
        for (unsigned int i = 1; i <= n; i++)//开始遍历
        {
            count += numOf1(i);
        }
        return count;
    }
};

思路3:数字规律总结。参考牛客评论区,一位一位的分析1出现的次数。

假设N=abcde,都是十进制的数字。如果计算百位上的数字,受到三方面因素。百位数字,百位之前的数字,百位之后的数字。

1.如果百位上是0的话,那么出现1的次数由百位之前的数字决定。比如15012,百位上出现1的情况是(00)100-199,(0)1100-1199,..10100-10199...14100-14199,从0到14,总共是15个,每段对应的是100个数。那就是15*100。

2.如果百位上是1的话,那么出现1的次数由百位之前的数字和百位之后的数字决定,比如15112,除了上面分析的那些(00)100-199,(0)1100-1199... 14100-14199这15*100个数之外,还多了15100-15112,这些是113个数字,也就是百位之后的数字+1.

3.如果百位上的数字大于1的话,那么出现1的次数由百位之前的数字决定,比如15212,那么除了上面分析的那些(00)100-199,(0)1100-1199... 14100-14199这15*100个数之外,还多了15100-15199,相当于是(15+1)*100个数字。


class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        int count = 0;//1的个数

        int i = 1; //当前位数,从个位开始遍历

        int current = 0,after = 0, before = 0;//记录三个位置的值
        while ((n / i) != 0)
        {
            current = (n / i) % 10;//,先处理n,再得到当前位。
            before = n / (i * 10);//整除i*10,得到的是高位数字
            after = n - (n / i) * i;//得到低位数字

            if (current == 0)
            {
                count += before * i;
            }
            else if (current == 1)
            {
                count += before * i + after + 1;
            }
            else
                count += (before + 1) * i;
            i = i * 10;//i往前进位

        }
        return count;
    }

};

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值