寫在前面
今天來聊一聊前端面試**現頻率非常高的一種演算法思想——「遞迴」。
先看下幾個常見的面試題:假如樓梯有n個台階,每次可以走1個或2個台階,請問走完這n個台階有幾種走法❓
如何用遞迴思想實現深拷貝❓
如何用遞迴思想實現陣列的扁平化❓
你可以先思考一下如何回答上邊的問題,然後帶著答案來閱覽接下來的內容。
如何編寫遞迴**❓
遞迴思想在前端面試中非常常見,除了上面的一些題目之外,二叉樹的前中後序遍歷,斐波那契數列等都用到了遞迴的思想。簡單地理解遞迴就是:自己呼叫自己。那如何編寫遞迴的**呢❓ 在筆者看來:
主要有兩個關鍵步驟:
function sum(n) return total}複製**
那如何改為遞迴的寫法呢?
第一步: 寫出遞迴公式
細心觀察就會發現,其實就是n與n-1和n-2的關係
sum(n) = sum(n-1) + n·········sum(100) = sum(99) + 100sum(99) = sum(98) + 99·········sum(5) = sum(4) + 5sum(4) = sum(3) + 4sum(3) = sum(2) + 3sum(2) = sum(1) + 2sum(1) = 1複製**
將如上轉化成遞迴公式就是
function sum(n) 複製**
第二步:找出終止條件遞迴公式寫出來了,那麼遞迴**就完成了一大半。現在來看一下上述問題的終止條件是什麼呢,即sum(1)= 1;
結合遞迴公式和終止條件,1+2+3+4+...+n求和的遞迴**如下:
function sum(n) 複製**
面試題1: 樓梯問題
假如樓梯有n個台階,每次可以走1個或2個台階,請問走完這n個台階有幾種走法❓
按照我們上面的思路,先寫出遞迴公式。那這道題我們如何去找出遞迴公式呢。假設有3個台階,我們可以有3種走法:
1 1 11 22 1複製**
第一種是每次都是走1個台階。第二種是第一步走1個台階,第二步走2個台階。第三種是第一步走2個台階,第二步走1個台階。
寫出遞迴公式:
那如果有n個台階呢?我們認真思考下就會發現,第1步的走法有兩類:第一種是第一步走1個台階,第二種是第二步走2個台階。所以n個台階的走法就可以分為:走完1個台階後的n-1種走法,加上走完2個台階後的n-2種走法,用遞迴公式表示就是:
function climbstairs(n) 複製**
找到終止條件:
climbstairs(n) = climbstairs(n-1) + climbstairs(n-2)climbstairs(n-1) = climbstairs(n-2) + climbstairs(n-3)·········climbstairs(5) = climbstairs(4) + climbstairs(3)climbstairs(4) = climbstairs(3) + climbstairs(2)climbstairs(3) = climbstairs(2) + climbstairs(1)climbstairs(2) = 2climbstairs(1) = 1複製**
從上面的推導可以看出:終止條件為:
climbstairs(2) = 2climbstairs(1) = 1複製**
綜上所述,解決爬樓梯的**如下:
function climbstairs(n) 複製**
當然,可以對上述題目做乙個memorize操作,效能會好很多:
var calculated = function climbstairs(n) else if (n == 2) else if(!calculated[n-2]) return calculated[n-1] + calculated[n-2] }}複製**
解決完爬樓梯問題之後,思考下斐波那契數列問題的求解,有木有發現是一樣的問題和思路:)
面試題2:實現深拷貝
如何用遞迴思想實現深拷貝❓如果要實現深拷貝那麼就需要考慮將物件的屬性, 與屬性的屬性,都拷貝過來, 這種情況下就非常適合使用遞迴思想來解決,在拷貝的適合判斷屬性值的型別,如果是物件則遞迴呼叫deeplclone函式,否則直接返回該屬性值:
var deepcopy = function(obj) ; for (var key in obj) } return newobj;}複製**
面試題3:如何把陣列拍平
如何用遞迴思想實現陣列的扁平化❓即如何把[1, [2], [3, [4, [5]]]]拍平得到[1,2,3,4,5]❓
const flatten = (arr) => else }) return result;};const arr = [1, [2, [3, 4, 5]]];console.log(flatten(arr)); // [1, 2, 3, 4, 5]複製**
總結
編寫遞迴**的關鍵在於找出遞迴公式和終止條件,最後將它們翻譯成**。遞迴**雖然比較簡潔。但是也有很多弊端,如效能不是很高效,這時候要做memorize等一些操作來優化效能。容易產生堆疊溢位等問題,所以我們在寫**的時候要注意這些。
前端面試演算法
演算法一般考得不難,不過基本每一次面試都會考到,常考的演算法有 排序演算法 詳見排序演算法解析 字串中找出最長最多重複的子串 js實現 字串中最長最多重複的子串 動態規劃,參見揹包問題 js實現動態規劃例項 層次遍歷二叉樹 遍歷二叉樹方法 加油站問題 貪心演算法 js實現加油貪心演算法 二分法 js...
讓前端面試不再難(常見演算法)
昨天聊了乙個演算法題,今天接著聊!多聊幾個。1 拍平陣列 多維陣列變成一維陣列 let arr 1,2,3,4 5,6,7 8 1,2,3,4,5,6,7,8 這個有很多方法,我們一一說來 第一種遍歷陣列,遍歷過程遇到陣列遞迴。function flatten arr,newarr return n...
前端面試經典演算法 柯里化
已知 fn 為乙個預定義函式,實現函式 curryit,呼叫之後滿足如下條件 返回乙個函式 a,a 的 length 屬性值為 1 即顯式宣告 a 接收乙個引數 呼叫 a 之後,返回乙個函式 b,b 的 length 屬性值為 1 呼叫 b 之後,返回乙個函式 c,c 的 length 屬性值為 1...