剑指offer ( 面试题 32) -- 从1到n整数中1出现的个数

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

解题思路 : 入下图所示将数据中每一位拿出来单独处理 , 为一位记为low

  1. 个位   : 从 1 增加到n ,没增加 1 , low就会增加 1 , 当low增加到 9 时就又会从 1 开始从新计算 , 而1--9 出现的周期次数取决于高位的大小 , 
  • 以下图为例 : 从1--n 的增长过程中 , 1--9 一共出现了45次 , 而当 low 大于 1 时 , 在第46次周期中 1 又出现了一次 , 所以个位上 1 出现的次数 count = high*1 + 1 = 46;  
  • 当为 450 时 , low为 0 时 , 这是 count =  high*1 = 45 ;

 

                                                      

  1.  十位   :  如下图所示 , 和上面的方式一样 , 只不过每增加10 , low才会增加 1 , 即 high*10 , 下图中 , low大于 1 ,证明在第5次周期中出现了 10 次 1 ,  count = high*10 + 10 ;
  • 如果是407 , low 为 0 , 证明 第4次周期后就停止了 , count = high*10 = 50 ;
  • 如果是417 , low 为 1 , 第5次周期中 1 出现的次数就和个数数有关 , 用 digit 记录个位数字 , count = high*10 + digit + 1

 

                                                      

  • 总结 : 在计算 1 的个数是 , 就可以归结为个位和更高位
  1. 对个位来说  当个位大于0 , 那么 1 出现的次数为 high + 1                                                                                                                             当个位等于0 , 那么 1 出现的次数为 high
  2. 对其它位来说,记每一位的权值为base,位值为high,该位之前的数是digit,举例如图 base 开始为 10

则:

  • 若low为0,则1出现次数为 high*base
  • 若low为1,则1出现次数为 high*base + digit + 1
  • 若low大于1,则1出现次数为 high*base + base

                                                         

  • 457 = ( 45 * 1 + 1) + ( 4 * 10 +10) + ( 0 * 100 + 100)
  • 407 = ( 45 * 1 + 1) + ( 4 * 10  + ( 0 * 100 + 100)
  • 417 = ( 41 * 1 + 1) + ( 4 * 10 + 7 + 1) + ( 0 * 100 + 100)

代码如下 : 

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        if(n<1)
            return 0;
        int base=1;
        int high=0;
        int low=n;
        int count=0;
        while(low){
            high=low%10;
            low/=10;
            count+=low*base;
            if(high==1)
                count+=(n%base+1);
            if(high>1)
                count+=base;
            base*=10;
        }
        return count;
    }
};

 

出处 ( 传送门 )  -- https://blog.csdn.net/yi_afly/article/details/52012593#commentBox

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值