別再翻了,面試二叉樹看這 11 個就夠了~

一隻不甘平凡的小鹿發表於2019-09-13

寫在前邊

資料結構與演算法:

不知道你有沒有這種困惑,雖然刷了很多演算法題,當我去面試的時候,面試官讓你手寫一個演算法,可能你對此演算法很熟悉,知道實現思路,但是總是不知道該在什麼地方寫,而且很多邊界條件想不全面,一緊張,程式碼寫的亂七八糟。如果遇到沒有做過的演算法題,思路也不知道從何尋找。面試吃了虧之後,我就慢慢的做出總結,開始分類的把資料結構所有的題型和解題思路每週刷題做出的系統性總結寫在了 Github。歡迎關注和 star: 「資料結構與演算法倉庫

PS:如果你剛剛在學習資料結構和演算法,請務必把最簡單的題弄懂,所有的入門的資料結構與演算法從簡單到複雜進行了全面的梳理。
初學者必會的 30 道資料結構與演算法

如果你對資料結構和演算法有了一定的瞭解和認識,上邊的入門演算法題已經可以輕鬆實現,那麼可以嘗試著解決 LeetCode 上總結的 30 道題,我把解題思路、測試用例、程式碼實現做了詳細的整理,建議先自己嘗試的解決哦,收藏 + 關注,歡迎 Star。「必會的 30 道 LeetCode 經典演算法題

網路協議原理:

除了演算法之外,面試最注重的就是網路原理,因為我本身上的學校很爛,課上只是講點皮毛,當時也沒重視這一塊,所以在大三面試的時候吃了大虧,然後開始重視了起來,這部分雖然理論上偏多,但是從最基礎的開始學習需要有個引導,上來就是 TCP 和 HTTP,想必學起來很吃力吧。然後我嘗試著去根源上學習網路原理,為什麼會有這些,所以邊學習,邊整理成了文章分享給學習網路原理這一塊的內容,每週 Github 都會更新~ 「猛戳這裡檢視倉庫


— 一下是正文 ----

《劍指 offer》是準備資料結構與演算法面試的一本好書,裡邊很多面試手寫演算法很多的注意的問題,但是基本都是用 C++ 實現的,書中每章節的分類都是按照效能和消耗以及手寫程式碼的注意的幾大點進行了分類,針對每個不同的點,進行資料結構與演算法的混合實現。

二遍刷題,發現了還可以根據自身情況進行整理和分類。全部程式碼是用 JS 書寫,都經過 Leetcode 標準測試(小部分Leetcode 沒有的題目),對所有的演算法題的特點進行總結分類,手寫演算法中,如何考慮到全部的邊界條件;如果快速多種思路解決,如何將思路快速的轉化為程式碼,這是這一篇重點分享的地方。

二叉樹題目共有 11 題,我把這 11 題書中對實現方法和思路有詳細的講解,但是對於個人來說,以後遇到陌生的二叉樹的題目怎麼進行解決,通過對 11 個題的分析、整理,得出以下幾個步驟,首先先來看這 11 個二叉樹經典演算法題。

PS:如果你已經做過這幾道題,而且能夠順利的手寫出來,不妨滑到最底部,希望最後的二叉樹思路、測試用例以及程式碼編寫的總結對你在面試中有所幫助(這篇文章精華所在)。


11 道精華二叉樹面試題

1.1 面試題7:重建二叉樹

已知前序遍歷為{1,2,4,7,3,5,6,8},中序遍歷為{4,7,2,1,5,3,8,6},它的二叉樹是怎麼樣的?

1、思路

根據前、中序遍歷的特點,(根左右、左根右),先根據前序遍歷確定根節點,然後在中序遍歷知道該根節點的左右樹的數量,反推出前序遍歷中左子樹的結點有哪些。根據該思路進行遞迴即可完成二叉樹的重建。

2、 測試用例

  • 完全二叉樹、非完全二叉樹 —— 普通測試。
  • 只有左子節點二叉樹,只有右子節點、只有一個結點的二叉樹 —— 特殊二叉樹測試。
  • 空樹、前序和中序不匹配 —— 輸入測試。

3、程式碼實現

 1 // 定義結點
 2 // class TreeNode{
 3 //     constructor(data){
 4 //         this.data = data;
 5 //         this.left = null;
 6 //         this.right = null;
 7 //     } 
 8 // }
 9
10 // 引數:前序遍歷陣列 ~ 中序遍歷陣列
11 const reConstructBinaryTree = (pre, vin)=>{
12    // 判斷前序陣列和中序陣列是否為空
13    if(!pre || pre.length === 0 || !vin || vin.length === 0){
14        return;
15    }
16    // 新建二叉樹的根節點
17    var treeNode = {
18        val: pre[0]
19    }
20    // 查詢中序遍歷中的根節點
21    for(var i = 0; i < pre.length; i++) {
22        if (vin[i] === pre[0]) {
23            // 將左子樹的前中序遍歷分割開
24            treeNode.left = reConstructBinaryTree(pre.slice(1, i+1), vin.slice(0, i));
25            // 將右子樹的前中序遍歷分割開
26            treeNode.right = reConstructBinaryTree(pre.slice(i+1),vin.slice(i+1));
27        }
28    }
29    // 返回該根節點
30    return treeNode;
31 }
32
33 let pre = [1,2,4,7,3,5,6,8]; // 前序遍歷
34 let vin = [4,7,2,1,5,3,8,6]; // 中序遍歷 
35 console.log(reConstructBinaryTree(pre,vin));

1.2 二叉樹的下一節點

給定一個二叉樹的節點,如何找出中序遍歷的下一節點。有兩個指向左右子樹的指標,還有一個指向父節點的指標。

面試題8:[題目解析]


1.3 樹的子結構

輸入兩棵二叉樹 A 和 B,判斷 B 是不是 A 的子結構。

面試題26:[題目解析]


1.4 二叉樹的映象

請完成一個函式,如果一個二叉樹,該函式輸出它的映象。

面試題27:[題目解析]


1.5 對稱二叉樹

請實現一個函式,用來判斷一棵二叉樹是不是對稱的。如果一棵二叉樹和它的映象一樣,那麼它是對稱的。

面試題28:[題目解析]


1.6 從上到下列印二叉樹

從上到下列印出二叉樹的每個節點,同一層的節點按照從左到右的順序列印。(按層遍歷二叉樹)

面試題32:[題目解析]


1.7 二叉樹的後序遍歷序列

輸入一個整數陣列,判斷該陣列是不是某二叉搜尋樹的後續遍歷。如果是返回 true,如果不是返回 false。假設輸入的任意兩個數字互不相同。

面試題33:[題目解析]


1.8 二叉樹和為某一值路徑

輸入一棵二叉樹和一個整數,列印出二叉樹中節點值的和為輸出整數的所有路徑。從樹的根節點開始往下一直到葉子節點所經過的節點形成一條路徑。

面試34:[題目解析]


1.9 序列化二叉樹

請實現兩個函式,分別用來序列化二叉樹和反序列化二叉樹。

面試題37:[題目解析]


1.10 二叉樹的第 K 大節點

給定一棵二叉搜尋樹,請找出其中的第 K 大節點。

面試題54:[題目解析]


1.11 二叉樹的深度

輸入一棵二叉樹的根節點,求該樹的深度。從根節點到葉子節點依次經過的節點(包含根、葉子節點)形成樹的一條路徑,最長路徑的長度樹的深度。

面試題55:[題目解析]


總結歸納

通過《劍指 offer》以上十一個題,不是做過之後就記住了這麼簡單,而是通過以上二叉樹題型的總結歸納,能不能舉一反三,總結出二叉樹面試題的解題思路,以後遇到二叉樹相面試題能不能通過上邊總結出來的步驟進行思考獨立解決,這是這篇文章的重點。下面就分別通過解題思路、測試用例以及編寫程式碼進行深入總結。

一、解題思路總結

1、根據樹前(根左右)、中(左根右)、後(左右根)序遍歷的規律來解決問題。

通過二叉樹的遍歷來找到規律,從而找到解題思路。

  • 重建二叉樹

    根據前、中序遍歷,找到二叉樹的根節點和左右子樹的規律,然後遞迴構建二叉樹。

  • 二叉樹的下一節點

    根據中序遍歷,找出包含任何節點的一下節點的所有可能情況,然後根據情況分別進行判斷。

  • 二叉樹的後續遍歷序列

    通過中序遍歷找到列印二叉樹結點的規律,可以判斷此後續遍歷是否為二叉樹。

  • 二叉樹和為某一值的路徑

    選擇二叉樹的遍歷,對每個節點進行儲存判斷,然後根據二叉樹葉子節點的特點,進行對問題的解決。

  • 二叉樹的第 K 大結點

    中序遍歷的結果是從小到大,然後倒數找到第 K 大資料。

  • 序列化二叉樹

    遍歷二叉樹,遇到 null 轉化為特殊符號。


2、根據樹的結構尋找規律來解決問題

通過二叉樹的特點:左子節點小於父節點、右子節點大於父節點、樹的節點可以進行遞迴等,以上特點又是更好的幫我們解決思路。

  • 樹的子結構

    根據子結構和主體樹的特點,對其樹的結構進行分析,可以找到解題的思路。

  • 映象二叉樹

    觀察映象二叉樹的左右子節點交換特點,可以找到解題思路。

  • 對稱二叉樹

    觀察對稱二叉樹有什麼特點,在結構上和遍歷上尋找特點和規律,可以找到解題思路。

  • 按層遍歷二叉樹

    根據二叉樹每層節點的結構關係(父子關係),可以進行每層遍歷,通過上層找到下層的遍歷結點。

  • 反序列化二叉樹

    根據遍歷的規律和二叉樹的規律,將遍歷結果生成一棵二叉樹。


二、測試用例

通過以上題目中,我將測試用例分為三大種,測試程式碼的時候,在這三大種進行想就可以了。

  • 普通測試
  • 特殊測試
  • 輸入測試

1、普通測試

普通測試從兩個方面去想,第一個方面就是問題的本身,比如對稱二叉樹的判斷,普通測試就是分別輸入一個對稱二叉樹和非對稱二叉樹進行測試。第二個方面就是問題本身沒有什麼可以找到的測試,比如按層遍歷二叉樹,它的普通測試就是分別輸入完全二叉樹(普通二叉樹也可以),非完全二叉樹進行測試。


2、特殊測試

特殊測試強調的是樹的特殊性,特殊的二叉樹就那麼幾個,比如:只有左子節點的二叉樹、只有右子節點的二叉樹、只有一個節點的二叉樹、沒有結點的二叉樹。


3、輸入測試

輸入測試,顧名思義,要對使用者輸入的引數進行判斷,比如,你輸入一棵樹,要判斷是否為空。再比如,求最大 K 結點,對 K 的取值範圍進行判斷。


三、程式碼編寫

將二叉樹的解題思路轉化為程式碼除了熟練最基本的二叉樹的增、刪、改、查之外,最重要的就是二叉樹的遞迴,因為二叉樹的結構決定了用遞迴解決二叉樹問題更加簡便。但是遞迴的書寫並不僅簡單,因為它有遞和歸的過程,大腦並不能更好的去處理這些,可以去看之前總結遞迴的文章《資料結構與演算法之遞迴系列》。

書寫二叉樹遞迴問題有一點特別重要,不要嘗試的去想那個遞迴的過程,而是先去尋找到遞迴的終止條件,然後對每次遞迴的結果進行判斷,然後讓他遞迴去吧,再次強調千萬別去思考過程。

後記

刷了一遍劍指 offer 沒有領略到這些題的精華所在,然後開始刷第二遍、第三遍、第四遍… 逐漸的對同一型別的題做出總結,第一週完成了所有二叉樹面試題的總結,下一週會選擇下一型別面試題進行攻克,打算用兩個月的時間,將劍指 offer 所有的面試題型進行體系化的總結、歸納,邊學習、邊分享。「猛戳劍指 offer 倉庫,和我一起打卡


下一篇:動畫:面試如何輕鬆手寫連結串列?


推薦閱讀:

1、動畫:用動畫給面試官解釋 TCP 三次握手過程

2、動畫:用動畫給女朋友講解 TCP 四次分手過程


❤️ 不要忘記留下你學習的腳印 [點贊 + 收藏 + 評論]

文章都看完了,為何不妨點個贊呢?嘻嘻,那就說明你很自私,你怕那麼好的文章讓別人也看到。開個小小玩笑。

其實我也很自私,我把我的一直以來堅持原創的公眾號:「小鹿動畫學程式設計」偷偷給你,裡邊匯聚了小鹿以動畫形式講解的資料結構與演算法、網路原理、Web 等技術文章。
在這裡插入圖片描述

動一動你的小手,點贊就完事了,每個人出一份力量(點贊 + 評論)就會讓更多的學習者加入進來!非常感謝! ̄ω ̄=


作者Info:

【作者】:小鹿

【原創公眾號】:小鹿動畫學程式設計。

【簡介】:和小鹿同學一起用動畫的方式從零基礎學程式設計,將 Web前端領域、資料結構與演算法、網路原理等通俗易懂的呈獻給小夥伴。先定個小目標,原創 1000 篇的動畫技術文章,和各位小夥伴共同努力一起學習!公眾號回覆 “資料” 送一從零自學資料大禮包!

【轉載說明】:轉載請說明出處,謝謝合作!~

相關文章