1. 程式人生 > >《演算法筆記》8. 二叉樹的遞迴思維實戰

《演算法筆記》8. 二叉樹的遞迴思維實戰

[TOC] # 1 二叉樹的遞迴套路 1、 可以解決面試中的絕大部分二叉樹(95%以上)的問題,尤其是樹形dp問題 2、 其本質是利用遞迴遍歷二叉樹的便利性,每個節點在遞迴的過程中可以回到該節點3次 ==具體步驟為:== 1. 假設以X節點為頭,假設可以向X左樹和右樹要任何資訊 2. 在上一步的假設下,討論以X為頭結點的樹,得到答案的可能性(最重要),常見分類是與X無關的答案,與X有關的答案 3. 列出所有可能性後,確定到底需要向左樹和右樹要什麼樣的資訊 4. 把左樹資訊和右樹資訊求全集,就是任何一顆子樹都需要返回的資訊S 5. 遞迴函式都返回S,每顆子樹都這麼要求 6. 寫程式碼,在程式碼中考慮如何把左樹資訊和右樹資訊整合出整棵樹的資訊 ## 1.1 二叉樹的遞迴套路深度實踐 ### 1.1.1 例一:判斷二叉樹平衡與否 給定一棵二叉樹的頭結點head,返回這顆二叉樹是不是平衡二叉樹 > 平衡樹概念:在一棵二叉樹中,每一個子樹,左樹的高度和右樹的高度差不超過1 > 那麼如果以X為頭的這顆樹,要做到平衡,那麼X的左樹要是平衡的,右樹也是平衡的,且X的左樹高度和右樹高度差不超過1 > 所以該題,我們X需要向左右子樹要的資訊為,1.高度 2. 是否平衡 ```Java package class08; public class Code01_IsBalanced { public static class Node { public int value; public Node left; public Node right; public Node(int data) { this.value = data; } } public static boolean isBalanced1(Node head) { boolean[] ans = new boolean[1]; ans[0] = true; process1(head, ans); return ans[0]; } public static int process1(Node head, boolean[] ans) { if (!ans[0] || head == null) { return -1; } int leftHeight = process1(head.left, ans); int rightHeight = process1(head.right, ans); if (Math.abs(leftHeight - rightHeight) > 1) { ans[0] = false; } return Math.max(leftHeight, rightHeight) + 1; } public static boolean isBalanced2(Node head) { return process2(head).isBalaced; } // 左、右要求一樣,Info 表示資訊返回的結構體 public static class Info { // 是否平衡 public boolean isBalaced; // 高度多少 public int height; public Info(boolean b, int h) { isBalaced = b; height = h; } } // 遞迴呼叫,X自身也要返回資訊Info。 // 解決X節點(當前節點)怎麼返回Info資訊 public static Info process2(Node X) { // base case if (X == null) { return new Info(true, 0); } // 得到左樹資訊 Info leftInfo = process2(X.left); // 得到右樹資訊 Info rightInfo = process2(X.right); // 高度等於左右最大高度,加上當前頭結點的高度1 int height = Math.max(leftInfo.height, rightInfo.height) + 1; boolean isBalanced = true; // 左樹不平衡或者右樹不平衡,或者左右兩子樹高度差超過1 // 那麼當前節點為頭的樹,不平衡 if (!leftInfo.isBalaced || !rightInfo.isBalaced || Math.abs(leftInfo.height - rightInfo.height) > 1) { isBalanced = false; } // 加工出當前節點的資訊返回 return new Info(isBalanced, height); } // for test public static Node generateRandomBST(int maxLevel, int maxValue) { return generate(1, maxLevel, maxValue); } // for test public static Node generate(int level, int maxLevel, int maxValue) { if (level > maxLevel || Math.random() < 0.5) { return null; } Node head = new Node((int) (Math.random() * maxValue)); head.left = generate(level + 1, maxLevel, maxValue); head.right = generate(level + 1, maxLevel, maxValue); return head; } public static void main(String[] args) { int maxLevel = 5; int maxValue = 100; int testTimes = 1000000; for (int i = 0; i < testTimes; i++) { Node head = generateRandomBST(maxLevel, maxValue); if (isBalanced1(head) != isBalanced2(head)) { System.out.println("Oops!"); } } System.out.println("finish!"); } } ``` ### 1.1.2 例二:返回二叉樹任意兩個節點最大值 給定一棵二叉樹的頭結點head,任何兩個節點之間都存在距離,返回整棵二叉樹的最大距離 > 1、有可能最大距離和當前節點X無關,即最大距離是X左樹的最大距離,或者右樹的最大距離 > 2、最大距離跟X有關,即最大距離通過X。左樹離X最遠的點,到X右樹上離X最遠的點。即X左樹的高度加上X自身高度1,加上X右樹上的高度 > 結論:那麼根據遞迴套路,我們每次遞迴,需要返回X左樹的最大距離和高度,同理返回X右樹的最大距離和高度。Info包含最大距離和高度 ```Java package class08; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; public class Code08_MaxDistance { public static class Node { public int value; public Node left; public Node right; public Node(int data) { this.value = data; } } public static int maxDistance1(Node head) { if (head == null) { return 0; } A