从1到N的整数中1出现的次数

版权声明:本文为博主原创文章,欢迎转载,转载请声明出处! https://blog.csdn.net/hansionz/article/details/82728589

题目:输入一个整数N,输出从1到N所有整数中1的个数。例如,输入数10,输出为2。

解题思路一:遍历从1到N的所有数字,求出每个数中1的个数,然后累加起来,就是最终的结果。

代码实现:

//求出每个数中1的个数
int NmberOfI(unsigned int n)
{
    int number = 0;
    while (n)
    {
        if (n % 10 == 1)
        {
            number++;
        }
        n /= 10;
    }
    return number;
}
//求1到N所有整数中1的个数
int NumberOfOne(unsigned int n)
{   
    int number = 0;
    for (size_t i = 1; i <= n; i++)
    {
        number += NmberOfI(i);
    }
    return number;
}

对于上边的代码,假设每个数中有N个1,那么它的时间复杂度为O(n*n)。因为上述代码对于每个数都进行了除或者模运算,效率比较低。

解题思路二:以计算1-21345中的1的个数为例。把这段数分为1-13451346-21345两段计算。

  • 1.首先,我们先计算10000-19999这段中1的个数。分成两种情况,如果给的数超过20000,存在10000-19999这段,则1的个数为10000个;另一种情况是所给的数没有超过20000,比如说12345,那么在这段中1的个数则为2345+1=2346
  • 2.第二步,我们计算1346-21345这段中要多少个1。因为10000-19999的万位已经计算过了,那么就只剩下后边的四位了。因为这段既存在以1位万位的,也存在以2位万位的,所以我们可以把1346-21345分成两段1346-1134511346-21345。在每一段中,万位1的个数已经确定,剩下的四位,先确定一位为1,总共四种可能,剩下的三位取值在0-9,所以总共1的个数为2*4*10^3=8000种
  • 3.最后一步,是求1-1345这段,这段上边问题的子问题,是一个递归的问题。可以分成1-345346-1345两端计算,显然这里可以用递归解决。

代码实现:

int PowerBase10(unsigned int n)
{
    int result = 1;
    for (unsigned int i = 0; i < n; i++)
    {
        result *= 10;
    }
    return result;
}
int NmberOfI_op(const char* str)
{
    assert(str);
    if (*str<'0' || *str>'9' || *str == '\0')
        return 0;
    int first = *str - '0';
    int len = strlen(str);

    if (len == 1 && first == 0)
        return 0;
    if (len == 1 && first > 0)
        return 1;

    //1.以21345为例,第一段10000-19999
    int numfirstdigit = 0;
    //第一个数大于2,则万位有10000个1
    if (first > 1)
        numfirstdigit = PowerBase10(len - 1);
    //第一个数等于1,则万位有后边几位的数+1(12345万位位1有2346个)
    else if (first == 1)
        numfirstdigit = atoi(str + 1) + 1;
    //2.1346-21345(剩下的4位,1的位置可以有四种情况,1固定好之后,其他位有0-9十种情况,既4*10^3)
    //但是1346-21345应该分为两端1346-11345、11346-21345,所以是8*10^3个
    int numotherdigit = first*(len - 1)*PowerBase10(len - 2);
    //3.0-1035(和上述方法一样,采用递归解决)
    int numrecursion = NmberOfI_op(str + 1);
    //最后1的个数是前三步的和
    return numfirstdigit + numotherdigit + numrecursion;
}
//将数字转换为字符串方便计算
int NumberOfOne_op(int n)
{
    if (n <= 0)
        return 0;
    char str[50];
    //将一些内容格式化输入到字符串中
    sprintf(str, "%d", n);
    return NmberOfI_op(str);
}

猜你喜欢

转载自blog.csdn.net/hansionz/article/details/82728589