【剑指offer】面试题32-从1到n整数中1出现的次数

题目描述:

输入一个整数N,求出1~N这N个整数的十进制表示形式中 1出现的次数。比如输入12,从1~12这12个整数中包含1的数字有:1,10,11,12,1总共出现了5 次。


题目分析:

看到这个题目,大多数人的想法或许就是:循环遍历1~N中的每一个数,然后求出每个数中1的个数,然后求和。这样做的话,需要将N个数遍历一遍,然后将每个数的每一位遍历一次,时间复杂度是比较高的(大于O(N)),所以我们依然找规律去做这个题目。
假如给定的数据是24531.
我们可以将数据的范围(1~24531)分成2部分1~4531和4532~24531.然后求出每一个范围中1的个数,将结果进行相加即可。
在4532~24531中最高位出现1的个数,一共就是10000(10000~19999)个.
如果我给定的数据是12345,最高位出现1的个也是10000吗?显然不是。而是2345+1 = 2346(10000~12345)个。
那么剩下四位中1出现的个数又该如何计算呢?2*4*10^(5-2) == 8000个。
这个范围可以再分为2个范围,4532~14531和14532~24531.对于低4位,取任意一位是1(4种取法),其余3位就有10*10*10 == 1000种可能。
在1~4531这个范围中,我们就可以继续上边的步骤(递归实现)。


实现代码:

#include<iostream>
using namespace std;
#include<cassert>
//1~N的十进制表示中出现的次数
int Power(int n)
{
    int result = 1;
    for(int i = 0; i < n; ++i)
    {
       result *= 10;
    }
    return result;
}
int numberOf1(const char* str)
{
    if(*str < '0'|| *str > '9' || *str == '\0' || str == NULL)//字符串不正确,进而说明数据有误
       return 0;
    int length = strlen(str);
    int first = *str - '0';
    if(first == 0 && length == 1)//处理这种情况
       return 0;
    if(first > 0 && length == 1)//处理N是个位数的情况
       return 1;
    //假如给定的数是 24531  数字分为两部分 1~4531 和4532 ~ 24531
    //1,2计算的是~ 24531中的个数
    //3计算的是1~ 4531中的个数
    //1.计算~19999中出现的次数
    int CountFirstDigit = 0;
    if(first > 1)
       CountFirstDigit = Power(length-1);
    if(first == 1)
       CountFirstDigit = atoi(str+1)+1;
    //2.计算后面位中出现的次数
    int CountOtherDigits = first * (length -1) * Power(length - 2);
    //3.计算~4531中出现的个数
    int CountRest = numberOf1(str + 1);
    return CountFirstDigit+ CountOtherDigits + CountRest;
}
int GetCount(int n)
{
    if(n <= 0)
       return 0;
    char str[15];
    _itoa(n,str,10);//将输入的数字转为字符串,为了方便编写程序
    return numberOf1(str);
}
int main()
{
    int n = 0;
    cin>>n;
    cout<<GetCount(n)<<endl;
    system("pause");
    return 0;
}

总结:

这里我们之所以将数字转为字符串,是为了方便表示数字,当然不转换也是可以的,只是表示起来或许比较麻烦。
整数转换成字符串的函数:char* _itoa(int n,char* string,int radix);
n表示要转换的整数,转换之后的字符串存储在string中,radix是一个整数,表示n是radix进制的整数。
当然也可以使用sprintf函数进行转换。
int sprintf(char* buffer,const char* format…);
sprintf(buffer,”%s”,n);表示n以%d的形式写进buffer中,返回值是写进去的字节数。


关于这道题目就先分析到这里~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值