超级偶数(SuperEven)是指每一位都是偶数的正整数,例如:
0,2,4,6,8,20,22,24,26,28,40,...,88,200,202,...
要求写一个函数,输入项数n,返回数列第n项的值。
说实话,这个题目整整花了我三天时间去思考(数学比较弱,大神见笑)#手动捂脸#。
其实到最后我还是没有完成这个Kata,因为作者要求用少于30个字符的代码解决,我的解决方案再怎么压缩也100个字符左右了。万念俱灰的我还是决定看别人的答案,发现一共有4个人解出来了,答案都一致,非常精妙。但是吹毛求疵的讲,标答也是有瑕疵的。卖个关子,先看看我的解答:
简单介绍一下思路
首先是找规律,既然每一位都是偶数,那么超级偶数的每一位都可以表示为
m=2x*10N 的形式其中 0<=x<=4,N为位数,个位N=0,十位N=1以此类推。
那么每个一个超级偶数M都可以表示为

通过观察发现,位数的变化规律为第 5N-1 项到 5N - 1项的位数位N。可以得到第a项的位数为
  []代表取整数位
同时发现每一位的变化也是有规律的,比如个位0、2、4、6、8为每5次一循环,而十位则为25次一循环,根据规律可以得到
[]代表取整数位
整理一下思路,把公式整合起来,我们设项数为a,第a项的值为M,第a项的位数为N,可以得到

接下来将公式转为js代码
function superEven(n){ var e='',l = (Math.log(n) / Math.log(5)) | 0; while(l >= 0){ e += (n / Math.pow(5,l)).toString().split('.')[0] % 5 * 2; l--;
} return e; };
这里用到了字符串拼接而没有用数字加减,是考虑到了大数字情况下丢失精度的问题。
用'|0'进行位运算取整是为了缩短代码长度,但是后面发现在大数字情况下'|0'出现溢出问题,因此后面修改为了字符串截取小数点前面部分。
经过复杂的计算,我总算把答案拿出来了,然而30个字符解决问题是什么鬼。我想我肯定是从根本上就偏离的题主的想法,于是我怀着惴惴不安的心情浏览了提交上去的答案,结果简直让人震惊!不多说贴代码:
superEven=n=>n.toString(5)*2
不得不说,我确实搞的过于复杂了,万万没想到这竟然是一个5进制的数组。我相信对数字敏感的大神肯定一眼就能看出来了吧。
但是结束了吗,并没有,当我测试两段代码时发现,在超大数据的情况下,纯数学运算是会丢失精度的,但是字符串拼接则不会


上面的结果为我的代码,下面为转5进制方法,node环境下运行速度上几乎可以忽略不计,两者都是小于1ms。
但是下面方法在结果超过17位时,开始丢失精度,并且在超过20位时,强制使用科学计数法
综上所述,标准答案确实是精妙绝伦,令人拍案叫绝,但是我自身的答案也是有可取之处的。
说到底,做练习还是为了提升自我,虽然没能给出最优解,但是过程已经让我受益匪浅了。
如果喜欢我的文章,可以扫描二维码关注我的微信公众号
争取每天都分享一点我自己的开发和练习体验~