0~400中1出现了多少次?

     今天小菜无意间在社区看到一个讨论:“0~400中1出现了多少次?”。

     小菜看到大部分网友给出的算法是基于字符串的处理,思路大致是:把所有数字拼接成一个字符串,然后对字符串进行处理,进而获取出现次数。例如以下代码:

 1 /**
 2 *  网友版本
 3 *  找出"1"出现的次数
 4 **/
 5 function numberCount1(n){
 6     var a = []; 
 7     for (var i = 0; i <= n; i++) {
 8          a.push(i);
 9     }  
10     var s = a.join(''); 
11     return (s.length - s.replace(/1/g, '').length);
12 }

     也有高手用位运算处理,无奈太高深,小菜看不懂~~~

     其实如果只考虑400这样规整的整数,是有规律可循的,小菜给出一个通过计算得出出现次数的版本:

/**
*  小菜的版本
*  找出"1"出现的次数
*  只可以判断除了最高位,其它位全是0的整数。例如1、10、20、400、5000。
**/
function numberCount(n){
    var _n = parseInt(n) || 0,
        _z = _n.toString().length-1,
        _w = Math.pow(10,_z),
        _s = _n/_w,
        count = 0;
    
    if(_s > 1){
        count = count + _w;
    }
    
    if(_s === 1){
        count = count + 1;
    }
    
    count = count + (_w/10)*_s*_z;
    
    return count;
}

     通过字符串处理,当范围比较小的时候,速度、资源消耗还是可以接受的,但是如果数量级比较大,比如0~400000000,用字符串处理,显然效率太低,经过测试,浏览器页面直接崩溃。

     而用小菜给出的算法,计算0~400000000范围内1出现的次数,平均耗时15毫秒左右,但小菜这种算法,只能处理除了最高位,其它位全是0的整数。例如1、10、20、400、5000。

     小菜写这篇文章,不是为了炫耀自己的算法,而是要感谢社区的积极讨论,讨论不仅让我们思路开阔,更让我们变得善于思考。

     通过这个小小的算法,让大家明白:没有最好的算法,只有最合适的,在不同的应用场景,采用恰当的算法,才能真正提高系统效率。

 

posted @ 2015-03-03 12:04  杨元  阅读(1523)  评论(3编辑  收藏  举报