【剑指Offer】题32:整数中1出现的次数(从1到n整数中1出现的次数)

题目描述:

亲们!!我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他。问题是:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有110111213因此共出现6,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。

输入:

输入有多组数据,每组测试数据为一行。

每一行有两个整数a,b(0<=a,b<=1,000,000,000)

输出:

对应每个测试案例,输出ab之间1出现的次数。

样例输入:

0 5
1 13
21 55
31 99

样例输出:

1
6
4
7

 按每一位来考虑,

    1)此位大于1,这一位上1的个数有 ([n / 10^(b+1) ] + 1) * 10^b
    2)此位等于0,为 ([n / 10^(b+1) ] ) * 10^b
    3)此位等于1,在0的基础上加上n mod 10^b + 1

    举个例子:

    30143:
    由于3>1,则个位上出现1的次数为(3014+1)*1
    由于4>1,则十位上出现1的次数为(301+1)*10
    由于1=1,则百位上出现1次数为(30+0)*100+(43+1)
    由于0<1,则千位上出现1次数为(3+0)*1000
    注:以百位为例,百位出现1为100~199,*100的意思为单步出现了100~199,100次,*30是因为出现了30次100~199,+(43+1)是因为左后一次301**不完整导致。
    如果还不懂,自己拿纸和笔大致写下,找下规律,就能推导出来了!
    两外,需要注意一点:由于测试系统要求的输入数据最大为1,000,000,000,因此用int会溢出,要用long long,另外比较坑跌的一点是a可能比b大,居然都没有说明,有点坑了。
    AC代码如下:
  
  
#include<stdio.h>
 
/*
分别统计num各位上1出现的次数,
相加得到1出现的总次数
*/
long long CountNum1(long long num)
{
    if(num <= 0)
        return 0;
 
    long long count = 0;    //统计1出现的次数
    long long current;    //当前位
    long long base = 1; //当前位的基
    long long remain = 0;   //当前位为1时,后面位剩余的数(即不完整的部分)中1出现的次数
    while(num)
    {
        current = num%10;
        num = num/10;
 
        if(current > 1)
             count += (num+1)*base;
        else if(current == 1)
            count += num*base + (remain+1);
        else
            count += num*base;
     
        //下一位要用到的基和剩余不完整部分值
        remain += current*base; 
        base *= 10;
    }
 
    return count;
}
 
int main()
{
    long long a,b;
    //a,b的大小不定
    while(scanf("%lld %lld",&a,&b) != EOF)
    {
        long long result;
        if(a > b)
            result = CountNum1(a) - CountNum1(b-1);
        else
            result = CountNum1(b) - CountNum1(a-1);
 
        printf("%lld\n",result);
    }
    return 0;
}
/**************************************************************
    Problem: 1373
    User: tcals
    Language: C
    Result: Accepted
    Time:0 ms
    Memory:912 kb
****************************************************************/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值