遞歸基本上是一個必考的算法題,它是實現程序計算過程中描述過程的基礎模式之一,可見這是極其重要的。前端考察這個的原因,多數是在於看看面試者對於一些基礎算法的了解程度,以及思考程度。
題目:一個數組“var meta = [1,2,[3,4,[5]],6,[7,[8,9,[10,11,[12]]]]];”,通過遞歸的方式依次取出這個數組中的數據。
-
最簡單的方式是設定一個函數,傳入這個數組,然后判斷其中的值是否為數組。
-
如果為數組,那么繼續調用當前的函數,將這個值傳入。
-
如果不為數組,那么就將值return出來,或者push到某個新數組里。
function fillArray(array,result){
var count = array.length;
var i = 0;
for(;i<count;++i){
var temp = array[i];
if(Array.isArray(temp)){
fillArray(temp,result); } else {
result.push(array[i]); } } }
var result = [];
fillArray(meta,result);
// 遞歸的結果console.log('遞歸處理的結果:',result);
顯然上述不是一個最優的答案,這個時候,面試官想要看的可能就是你主動思考的能力了,想一想,這個是不是可以優化一下,如果可以怎么辦?
我們先從結果來看:
-
如果一個結果已經確定,在第二次調用時是否可以從內存里直接讀,而不需要再緩存?
-
設計好一個簡單的Key/Value緩存
-
在循環時,增加一個條件判斷,如果緩存中存在,那么直接從緩存讀取結果
var resultMap = {};
function fillArrayII(array,result){
var count = array.length;
var i = 0;
if (!count){
return []; }
for(;i<count;++i){
var temp = array[i];
var g = resultMap[temp];
if(g){
result.push(g); } else {
if (Array.isArray(temp)){
fillArrayII(temp,result); } else {
result.push(temp); } } } }
var date1 = new Date();
var time1 = date1.getTime();
var r = [];
fillArrayII(meta,r);
var date2 = new Date();
var time2 = date2.getTime();
console.log('no cache time : ',time2 - time1);
var date3 = new Date();
var time3 = date3.getTime();
var f = [];
fillArrayII(meta,f);
var date4 = new Date();
var time4 = date4.getTime();
console.log('cache time : ',time4 - time3);
大家可以看一下優化的結果:
無緩存的420ms,而緩存過的393ms,足足提升了27ms,雖然這個空間不大,但是如果當遞歸足夠深時,可以節省大量的時間。不過緩存,需要對數據結構有一定的設計,這是一個前提。
那么除了緩存之外,最常用的優化方式應該算尾遞歸了,通俗易懂的說,尾遞歸就是把計算結果放到調用者函數的尾部,頂部的返回值越簡單越好,而尾巴的返回可能是越來越復雜的計算。
這里只是一個“拋磚引玉”,一般正常情況下遞歸都可以用迭代來代替。如果你在寫完遞歸之后,再寫一個迭代的代替方案,並加以說明,我想你應該會受到青睞。