【编程之美】2.4从1到N中1出现的数目


题目描述:

给定一个十进制整数N,写出从1开始到N的所有整数,统计一下其中出现所有“1”的个数。

例如12,一共有1、10、11、12四个数中出现5次1。

问:

1、写出一个函数,返回1到N之间出现1的次数

2、满足条件f(N) = N 的最大的N是多少。



题目解析:


思路一:

我们用粗暴的方式,要求1的个数,那么我们就跟二进制中统计1的个数一样,我们从1->N遍历,对每一个数对10求余,判断是否为1,然后再除以10,不断循环。时间复杂度为O(NlgN)。

int CountOne(int n)
{
    int num = 0;
    int v;
    for(int i = 1;i <= n;++i){
        v = i;
        while(v){
            if(v%10 == 1)
                num++;
            v /= 10;
        }
    }

    return num;
}

思路二:

当我们分析这个题目的时候,会发现个位十位百位等出现1的数目是有规律的,毕竟对于个位说增加10会有又一次循环。
我们还是考虑比较通用的,也更方便我们分析,将题目换成:出现3的次数。对于456和314我们同时讨论:
(1)先判断百位的4,由于4比3大,百位出现了100次3。再考虑314的百位3,由于跟3相等,估百位出现3的次数为(14+1)。因为300也要算。
(2)再考察一下十位的5,由于5比3大,那么会有30-39,130-139,230-239,330-339,430-439一共50个数据,也就是说当十位大于3的时候出现的个数为(百位数+1)*10。再看看314,有30-39,130-139,230-239一共三十个数据,也就是说当十位小于3的时候,为——百位数*10 ,这时就不需要再加1了。但如果为332呢?十位出现的个数为(百位数*10 +个位数+1)
(3)分析个位的话,与十位相同。


总结:

N = abcde  对于百位来说受到三个方面的影响,更高位,百位,低位三者的影响:

1、c为0时,百位出现1的次数为(ab)* 100。

2、c为1时,百位出现1的次数为(ab)* 100 + cd + 1

3、c大于1时,百位出现1的次数为(ab+1)* 100


int CountOne_1(int n)
{
    int count = 0;
    int factor = 1;
    int lower,current,higher;

    while(n/factor != 0){
        lower = n - (n/factor)*factor;
        current = (n/factor)%10;
        higher = n/factor/10;
        switch(current){
        case 0:
            count += higher * factor;
            break;
        case 1:
            count += higher * factor + lower + 1;
            break;
        default :
            count += (higher + 1)*factor;
            break;
        }
        factor *= 10;
    }

    return count;
}


问题2:

详见《编程之美》136解释。

通过举例子来一点一点得出







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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值