本專題旨在分享刷Leecode過程發現的一些思路有趣或者有價值的題目。【當然是基於js進行解答】。
(這道題應該算是二叉樹的基礎題,建議還是學一下,不難且經典)
題目相關
- 原題地址: https://leetcode-cn.com/probl...
題目描述:
從上到下按層列印二叉樹,同一層的節點按從左到右的順序列印,每一層列印到一行,例如,給定二叉樹:
[3,9,20,null,null,15,7]
3 / \ 9 20 / \ 15 7
返回其層次遍歷結果:
[ [3], [9,20], [15,7] ]
Tips
考慮某些同學可能比較少用js來刷leetcode,我們在這裡簡單介紹下,關於樹型別的資料輸入,在js裡的表示。 形如上題中的內容,給定二叉樹的輸入,其實並非一個陣列,而應該是如下所示: 每個節點是一個
object
const root = { val: 3, left: { // left表示當前節點的左側子節點 val: 9, left: null, // 對照上圖可以看到 節點9沒有左右子節點 right: null, }, right: { val: 20, left: { val: 15, // 對照上圖可以看到 節點15沒有左右子節點 left: null, right: null, }, right: { val: 7, // 對照上圖可以看到 節點7沒有左右子節點 left: null, right: null, }, } }
思路解析
這道題比較基礎,其實考的是BFS+層序遍歷,怎麼說呢?
首先 BFS(Breadth First Search)也就是廣度優先搜尋, 指的是在遍歷過程,每次總是優先遍歷當前節點的所有鄰接節點,將其放入一個佇列,比如上題的例子:
- step1: 首先準備一個空佇列(也就是陣列)
[ ]
,並且把根節點放入陣列中,也就是[3]
; - step2: 先取出佇列的最前面節點(此時佇列只有節點3,取出之後佇列置空), 然後把它的所有鄰接節點(在二叉樹裡面也就是左右子節點)按順序加入訪問佇列,所以此時佇列元素為
[9 20]
, - step3: 繼續按照第二步的規則,取出節點9,並把9的子節點放入佇列(無子節點);再把節點20取出,並且把節點20的子節點存入佇列,此時佇列剩餘元素為
[15, 7]
; - step4: 繼續按照第二步規則, 取出節點15, 並把子節點放入佇列(無子節點);再把節點7取出,並且把節點7的子節點存入佇列,此時佇列剩餘元素為
[]
, 佇列為空 結束整個過程 ;
仔細觀察以上的步驟,你發現了嗎?
- 除了第一步初始化資料,後續的所有步驟 都在按照第2步的規則重複;
觀察每一步的取出結果:
- step2, 取出[3];
- step3, 取出[9, 20];
- step4, 取出[15, 17];
這裡每一步的取出結果 正好就是題設要求的每一層遍歷的結果。
- 整個過程結束條件,就是節點佇列為空。
這道題講到這裡,其實大致思路就已經很清晰了,或者說,其實上面的步驟就已經是虛擬碼了(沒辦法,因為題目本身就非常典型-_-!)
- 首先第2步的規則肯定就是主函式,因為它全程一直迴圈;
- 其次,初始條件/結束條件分別對應的是 根節點入佇列,和佇列為空;
- 唯一的難點,在於如何優雅地處理【分層輸出】,而這一點 我建議大家直接看我最後貼地完整程式碼。
完整程式碼
那麼其實就可以直接看程式碼了:
var levelOrder = function(root) {
if (!root) { // 如果根節點都不存在 那直接結束
return [];
}
const nodes = [root]; // 初始化,對應前面分析裡地初始條件,
const res = [];
while(nodes.length > 0) { // 外層迴圈 當節點佇列為空時結束
const tempRes = [];
let isEmpty = false;
// 【注意點】這個內迴圈 也就是處理分層輸出地精髓所在,大家可以仔細揣摩下這個迴圈條件
// 嘗試回答這裡為什麼不採用 “i=0 ;i<nodes.length; i++”的形式
for(let i = nodes.length;i > 0 ; i--) {
const node = nodes.shift();
tempRes.push(node.val);
if(node.left) {
nodes.push(node.left);
}
if(node.right) {
nodes.push(node.right);
}
}
res.push(tempRes);
}
return res;
};
好了整體的題目算是基礎題, 就不畫動態圖了(畫圖很耗時), 但是想兩個問題給大家思考:
- 也就是程式碼塊裡的問題,為什麼內迴圈的條件不是
i=0 ;i<nodes.length; i++
? 如果是,會怎麼樣? - 如果本道題演變成輸出深度優先遍歷的結果,核心要點要怎麼改動?
如果能夠回答出上面的兩個問題,那基本上就理解了這個知識點!