超級偶數(SuperEven)是指每一位都是偶數的正整數,例如: 0,2,4,6,8,20,22,24,26,28,40,...,88,200,202,... 要求寫一個函數,輸入項數n,返回數列第n項的值。 說實話,這個題目整整花了我三天時間去思考(數學比較弱,大神見笑)#手動捂臉#。 其實到最後 ...
超級偶數(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位時,強制使用科學計數法
綜上所述,標準答案確實是精妙絕倫,令人拍案叫絕,但是我自身的答案也是有可取之處的。
說到底,做練習還是為了提升自我,雖然沒能給出最優解,但是過程已經讓我受益匪淺了。
如果喜歡我的文章,可以掃描二維碼關註我的微信公眾號
爭取每天都分享一點我自己的開發和練習體驗~