實現一個函數,檢查二叉樹是否平衡,平衡的定義以下,對於樹中任意一個結點,兩顆子樹的高度差不超過1。給定指向樹根結點的指針TreeNode* root,請返回一個bool,表明這棵樹是否平衡。函數
樹結構自身就是遞歸定義,不少問題均可以利用遞歸巧妙地實現,對於這道題,關鍵點有兩處:post
以前咱們作過樹的最大深度問題以及樹的遍歷問題,將二者結合起來,即可以解決這兩個關鍵點。
解題思路爲:ui
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ class Balance { public: bool isBalance(TreeNode* root) { if (!root) return true; int differ=Depth(root->left)-Depth(root->right); if (differ>1||differ<-1) return false; return isBalance(root->left)&& isBalance(root->right); //遞歸遍歷樹中全部結點 } //計算結點高度 int Depth(TreeNode *root) { if (!root) return 0; int L_high=Depth(root->left); int R_high=Depth(root->right); return (left>right) ? (left+1) : (right+1); } };
這道題中值得一提的是其中體現出的遞歸思想,源代碼中有兩處遞歸調用,而若是咱們去觀察的話,會發現它們的形式是不一樣的。isBalance函數中,問題的解決在遞歸調用函數以前,而在Depth函數中,遞歸調用函數在問題的解決以前。可是,這又有什麼不一樣呢?指針
咱們知道遞歸是一個調用並返回的過程,它要求待解決的問題能夠拆分爲不少個解法相同或相似的小問題,經過遞的過程由近及遠,到達臨界點(也就是結束條件)而後再開始歸,咱們常常搞不清楚的是在這樣一個過程當中,問題是如何一步步被解決的?code
以前看了一篇關於大腦理解遞歸的文章,裏面對於這一點講得很好,對於我理解遞歸起到了很大的幫助。
遞歸過程有不一樣的模式,而它們都有三個共同的要素:遞+結束條件+歸遞歸
function(大問題) { if (end_condition) { //結束條件 return ; } else { //先將一個大問題拆分爲小問題,當「遞」到「結束條件」返回的過程當中,再依次解決問題 recursive(小問題); // 遞 => 遞歸調用函數 solve questions; // 歸 => 問題的解決 } }
這種模式就對應於源代碼中的Depth函數,假如咱們給定一棵以下結構的二叉樹,get
咱們去分析Depth函數的遞歸流程,以下:it
從圖中能夠看出,程序的執行流程是遞歸調用函數(遞)→返回(結束條件)→解決問題(歸),問題是在遞歸調用返回的過程當中一步步被解決的。io
function(大問題) { if (end_condition) { //結束條件 return ; } else { //在將大問題逐步拆分爲小問題的同時去解決問題 solve questions; // 遞 => 問題的解決 recursive(小問題); // 遞 => 遞歸調用函數 } }
這種模式就對應於源代碼中的isBalance函數,依舊利用上面說起的二叉樹結構,去分析isBalance函數的遞歸流程,以下:function
從圖中能夠看出,程序的執行流程是解決問題(遞)→遞歸調用函數(遞)→返回(結束條件)→一步步返回上層(歸),每一次問題的解決都是在遞歸調用函數的過程當中(遞)便已經被解決,而不是在返回(歸)的過程當中。
對於遞歸思想的理解,有人曾作了一個形象的比喻:
你打開面前這扇門,看到屋裏面還有一扇門(這門可能跟前面打開的門同樣大小(靜),也可能門小了些(動)),你走過去,發現手中的鑰匙還能夠打開它,你推開門,發現裏面還有一扇門,你繼續打開,。。。, 若干次以後,你打開面前一扇門,發現只有一間屋子,沒有門了。 你開始原路返回,每走回一間屋子,你數一次,走到入口的時候,你能夠回答出你到底用這鑰匙開了幾扇門。
這種說法其實並不全面,它對應了模式1,在歸的過程當中一步步解決問題。
或許咱們能夠對其稍加修改,以對應模式2。
你打開面前這扇門,看到屋裏面還有一扇門(這門可能跟前面打開的門同樣大小(靜),也可能門小了些(動)),你走過去,發現手中的鑰匙還能夠打開它,你推開門,發現裏面還有一扇門,你繼續打開。。。而在打開門的過程當中,每走到一間屋子,你數一次, 若干次以後,你打開面前一扇門,發現只有一間屋子,沒有門了。 你開始原路返回,走到入口的時候,你能夠回答出你到底用這鑰匙開了幾扇門。
這兩種形式都有調用並返回(遞歸)的過程,不一樣點在於問題被解決的時機不一樣,有多是在遞的過程當中就已經被解決,也多是在歸的過程當中被解決。
以上是我對於遞歸的一些理解,可能會有不當之處,望指出Thanks♪(・ω・)ノ