二叉樹與分治

幾種常見的二叉樹:node

滿二叉樹 :除了葉子節點外,全部節點都有兩個兒子,深度爲 k 的滿二叉樹具備 2^k - 1 個節點。面試

徹底二叉樹 :若設二叉樹的高度爲h,除第h層外,其餘各層 (1 ~ h -1)層節點都達到最大個數,第h層的葉子節點從左到右依次排列。算法

平衡二叉樹(AVL) :是一棵平衡的二叉查找樹。任何一個節點的左右兩個兒子的高度差不超過1,而且其左右子樹都是平衡二叉樹。app

二叉查找樹(BST) : 左 < 根 < 右。(BST不必定是平衡二叉樹)ide

 

 

遇到二叉樹問題,就想一想整棵樹在該問題上的結果和左右子樹在該問題上的結果之間的聯繫。post

二叉樹問題經常伴隨着遍歷出現,基本的就有前序遍歷,中序遍歷,後續遍歷。三種遍歷的實現分爲遞歸實現和非遞歸實現,而遞歸實現又能夠分爲遍歷法和分治法。區分遍歷法能夠簡單想爲遍歷就是都是本身去作,而分治是分給本身的小弟去作。ui

通常分子二叉樹問題均可以使用分治,就是無腦的先丟給左子樹,而後無腦的丟給右子樹,獲得左右子樹的結果以後再考慮根節點。this

這裏就先給出三種遍歷的三種實現方法。前序遍歷:根左右    中序遍歷:左根右     後續遍歷:左右根spa

前序遍歷遍歷法:3d

 1  public ArrayList<Integer> preorderTraversal(TreeNode root) {
 2         // write your code here
 3         ArrayList<Integer> result = new ArrayList<Integer>();
 4         preorderHelp(result,root);
 5         return result;
 6     }
 7     public void preorderHelp(ArrayList<Integer> result , TreeNode root) {
 8         if (root == null) {
 9             return;
10         }
11         result.add(root.val);
12         preorderHelp(result, root.left);
13         preorderHelp(result, root.right);
14     }
View Code

前序遍歷非遞歸:

 1  public ArrayList<Integer> preorderTraversal(TreeNode root) {
 2         // write your code here
 3         ArrayList<Integer> result = new ArrayList<Integer>();
 4         if (root == null)
 5             return result;
 6         Stack<TreeNode> stack = new Stack<TreeNode>();
 7         stack.push(root);
 8         while(!stack.isEmpty()) {
 9             TreeNode node = stack.pop();
10             result.add(node.val);
11             if(node.right != null){
12                 stack.push(node.right);
13             }
14             if(node.left != null){
15                 stack.push(node.left);
16             }
17         }
18         return result;
19     }
View Code

前序遍歷分治算法:

 1  public ArrayList<Integer> preorderTraversal(TreeNode root) {
 2         // write your code here
 3         ArrayList<Integer> result = new ArrayList<Integer>();
 4         if (root == null) {
 5             return result;
 6         }
 7         result.add(root.val);
 8         ArrayList<Integer> left = preorderTraversal(root.left);
 9         ArrayList<Integer> right = preorderTraversal(root.right);
10         result.addAll(left);
11         result.addAll(right);
12         return result;
13     }
View Code

中序遍歷,後續遍歷的分治算法和遍歷算法與前序遍歷的區別僅僅是添加的順序不一樣。非遞歸算法有所區別。

中序遍歷非遞歸:

 1  public ArrayList<Integer> inorderTraversal(TreeNode root) {
 2         // write your code here
 3         ArrayList<Integer> result = new ArrayList<Integer>();
 4         TreeNode curNode = root;
 5         Stack<TreeNode> stack = new Stack<TreeNode>();
 6         while (curNode != null || !stack.isEmpty()) {
 7             while (curNode != null){
 8                 stack.push(curNode);
 9                 curNode=curNode.left;
10             }
11             curNode = stack.peek();
12             result.add(curNode.val);
13             stack.pop();
14             curNode = curNode.right;
15         }
16         return result;
17     }
View Code

後續遍歷非遞歸:

後續遍歷的非遞歸算法仍是有點難度的,主要是記錄是從上往下遍歷 仍是從左往上遍歷 仍是從右往上遍歷。使用兩個Node prev和cur,使用這兩個節點的關係來判斷是上述三種狀況的哪種,只有在第三種狀況下result中添加值。

 1 public ArrayList<Integer> postorderTraversal(TreeNode root) {
 2         // write your code here
 3         ArrayList<Integer> result = new ArrayList<Integer>();
 4         Stack<TreeNode> stack = new Stack<TreeNode>();
 5         TreeNode cur = root;
 6         TreeNode prev = null;
 7         if (root == null) {
 8             return result;
 9         }
10         stack.push(root);
11         while (!stack.isEmpty()) {
12             cur = stack.peek();
13             if (prev == null || prev.left == cur || prev.right == cur) { //traverse down the tree
14                 if (cur.left != null) {
15                     stack.push(cur.left);
16                 }
17                 else if (cur.right != null) {
18                     stack.push(cur.right);
19                 }
20             }
21             else if (cur.left == prev) {//traverse up the tree from the left
22                 if (cur.right != null) {
23                     stack.push(cur.right);
24                 }
25             }
26             else {
27                 result.add(cur.val);
28                 stack.pop();
29             }
30             prev = cur;
31         }
32         return result;
33     }
View Code

 後續遍歷非遞歸算法二,相似於前序遍歷,先獲得根右左到棧中,而後彈出。

 1 public ArrayList<Integer> postorderTraversal(TreeNode root) {
 2         // write your code here
 3         ArrayList<Integer> result = new ArrayList<Integer>();
 4         Stack<TreeNode> stack = new Stack<TreeNode>();
 5         TreeNode cur = root;
 6         TreeNode prev = null;
 7         if (root == null) {
 8             return result;
 9         }
10         stack.push(root);
11         while (!stack.isEmpty()) {
12             cur = stack.peek();
13             if (prev == null || prev.left == cur || prev.right == cur) { //traverse down the tree
14                 if (cur.left != null) {
15                     stack.push(cur.left);
16                 }
17                 else if (cur.right != null) {
18                     stack.push(cur.right);
19                 }
20             }
21             else if (cur.left == prev) {//traverse up the tree from the left
22                 if (cur.right != null) {
23                     stack.push(cur.right);
24                 }
25             }
26             else {
27                 result.add(cur.val);
28                 stack.pop();
29             }
30             prev = cur;
31         }
32         return result;
33     }
View Code

 

 

下面看看二叉樹問題的無腦左右子樹分治解決方案:

 

二叉樹的最大深度

1 public int maxDepth(TreeNode root) {
2         // write your code here
3         if (root == null)
4             return 0;
5         int left = maxDepth(root.left);
6         int right = maxDepth(root.right);
7         return Math.max(left, right) + 1;
8     }
View Code

 

平衡二叉樹

給定一個二叉樹,肯定它是高度平衡的。對於這個問題,一棵高度平衡的二叉樹的定義是:一棵二叉樹中每一個節點的兩個子樹的深度相差不會超過1。

分治算法實現,這裏須要注意的是分治的返回值有兩個,之前遇到過用-1來表明子樹不是平衡樹的狀況,以爲這種想法很好,其實不該該這樣,這樣帶來了二義性的問題。代碼仍是要有利於閱讀較好。

 1 public boolean isBalanced(TreeNode root) {
 2         // write your code here
 3         return isBalancedHelp(root).isBalanced;
 4     }
 5     public ReturnType isBalancedHelp(TreeNode root) {
 6         if(root == null) {
 7             return new ReturnType(0 , true);
 8         }
 9         ReturnType left = isBalancedHelp(root.left);
10         ReturnType right = isBalancedHelp(root.right);
11         int leftDepth = left.depth;
12         int rightDepth = right.depth;
13         int curDepth = Math.max(left.depth, right.depth)+1;
14         if (left.isBalanced && right.isBalanced) {
15             if (Math.abs(leftDepth - rightDepth) <= 1)
16                 return new ReturnType(curDepth, true);
17         }
18         return new ReturnType(curDepth , false);
19     }
20 class ReturnType {
21      int depth;
22      boolean isBalanced;
23      public ReturnType(int depth, boolean isBalanced) {
24          this.depth = depth;
25          this.isBalanced =isBalanced;
26      }
27  }
View Code

 

最近公共祖先

給定一棵二叉樹,找到兩個節點的最近公共父節點(LCA)。

最近公共祖先是兩個節點的公共的祖先節點且具備最大深度。

假設給出的兩個節點都在樹中存在。

遇到這類面試題,首先問有沒有指向父親的指針,有的話就簡單了,直接往上遍歷到根節點,獲得兩條路徑,而後查找第一個不一樣的。注意這裏假設的是必定有CA。

遞歸程序在包含AB時就返回LCA,只包含A就返回A,只包含B就返回B,不然返回null。

 1 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
 2         // write your code here
 3         if (root == null || root == A || root == B) {
 4             return root;
 5         }
 6         TreeNode left = lowestCommonAncestor(root.left, A, B);
 7         TreeNode right = lowestCommonAncestor(root.right, A, B);
 8         if (left != null && right!=null) {
 9             return root;
10         }
11         if (left != null) {
12             return left;
13         }
14         if (right != null) {
15             return right;
16         }
17         return null;
18     }
View Code

 

最近公共祖先 II

 

給一棵二叉樹和二叉樹中的兩個節點,找到這兩個節點的最近公共祖先LCA

 

兩個節點的最近公共祖先,是指兩個節點的全部父親節點中(包括這兩個節點),離這兩個節點最近的公共的節點。

 

每一個節點除了左右兒子指針之外,還包含一個父親指針parent,指向本身的父親。

 

 1 public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root,
 2                                                  ParentTreeNode A,
 3                                                  ParentTreeNode B) {
 4         // Write your code here   
 5         if (root == null || root == A || root == B) {
 6             return root;
 7         }
 8         HashSet<ParentTreeNode> hashSet = new HashSet<ParentTreeNode>();
 9 
10         while (A != null) {
11             hashSet.add(A);
12             A = A.parent;
13         }
14         while (B != null) {
15             if (hashSet.contains(B)) {
16                 return B;
17             }
18             B = B.parent;
19         }
20         return null;
21     }
View Code

 

最近公共祖先 III

給一棵二叉樹和二叉樹中的兩個節點,找到這兩個節點的最近公共祖先LCA。

兩個節點的最近公共祖先,是指兩個節點的全部父親節點中(包括這兩個節點),離這兩個節點最近的公共的節點。

返回 null 若是兩個節點在這棵樹上不存在最近公共祖先的話。

 注意事項

這兩個節點未必都在這棵樹上出現。

 1 public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode A, TreeNode B) {
 2         // write your code here
 3         return help(root, A, B).root;
 4     }
 5     public ResultType help(TreeNode root, TreeNode A, TreeNode B) {
 6         if (root == null) {
 7             return new ResultType(null, false, false);
 8         }
 9         ResultType left = help(root.left, A, B);
10         ResultType right = help(root.right, A, B);
11         if (left.root != null) {
12             return left; 
13         }
14         if (right.root != null) {
15             return right;
16         }
17         if (root == A) {
18             if (root == B) {
19                 return new ResultType(root, true, true);
20             }
21             if (left.containsB || right.containsB) {
22                 return new ResultType(root, true, true);
23             }
24             else {
25                 return new ResultType(null, true, false);
26             }
27         }
28         else if (root == B) {
29             if (left.containsA || right.containsA) {
30                 return new ResultType(root, true, true);
31             }
32             else {
33                 return new ResultType(null, false, true);
34             }
35         }
36         else {
37             if (left.containsA) {
38                 if (right.containsB) {
39                     return new ResultType(root, true, true);
40                 }
41                 else {
42                     return new ResultType(null, true, false);
43                 }
44             }
45             else if (left.containsB) {
46                 if (right.containsA) {
47                     return new ResultType(root, true, true);
48                 }
49                 else {
50                     return new ResultType(null, false, true);
51                 }
52             }
53             else {
54                 if (right.containsA) {
55                     return new ResultType(null, true, false);
56                 }
57                 else if (right.containsB) {
58                     return new ResultType(null, false, true);
59                 }
60                 else {
61                     return new ResultType(null, false, false);
62                 }
63         
64             }
65         }
66     }
67 class ResultType {
68     TreeNode root;
69     boolean containsA;
70     boolean containsB;
71     public ResultType (TreeNode root, boolean containsA, boolean containsB) {
72         this.root = root;
73         this.containsA = containsA;
74         this.containsB = containsB;
75     }
76 }
View Code

 

二叉樹的最大路徑和 II

給一棵二叉樹,找出從根節點出發的路徑中,和最大的一條。

這條路徑能夠在任何二叉樹中的節點結束,可是必須包含至少一個點(也就是根了)。

注意節點值可能爲負數。無腦分給左右兒子就行。

1 public int maxPathSum2(TreeNode root) {
2         // Write your code here
3         if (root == null) {
4             return Integer.MIN_VALUE;
5         }
6         int left = maxPathSum2(root.left);
7         int right = maxPathSum2(root.right);
8         return root.val+Math.max(0,Math.max(left, right));
9     }
View Code

 

二叉樹中的最大路徑和

給出一棵二叉樹,尋找一條路徑使其路徑和最大,路徑能夠在任一節點中開始和結束(路徑和爲兩個節點之間所在路徑上的節點權值之和)

 

 1 public int maxPathSum(TreeNode root) {
 2         // write your code here
 3         return maxPathSumHelp(root).any2Any;
 4     }
 5     public ResultType maxPathSumHelp(TreeNode root) {
 6         if (root == null) {
 7             return new ResultType(
 8                     Integer.MIN_VALUE, Integer.MIN_VALUE
 9             );
10         }
11         ResultType leftRes = maxPathSumHelp(root.left);
12         ResultType rightRes = maxPathSumHelp(root.right);
13         int root2Any = root.val
14                     + Math.max(0, Math.max(leftRes.root2Any,rightRes.root2Any));
15         int any2Any = root.val + Math.max(0,leftRes.root2Any)
16                                + Math.max(0,rightRes.root2Any);
17                                
18         any2Any = Math.max(any2Any,
19                 Math.max(leftRes.any2Any, rightRes.any2Any)
20         );
21         return new ResultType(root2Any, any2Any);
22     }
23 class ResultType {
24      int root2Any;
25      int any2Any;
26      public ResultType(int root2Any, int any2Any) {
27          this.root2Any = root2Any;
28          this.any2Any = any2Any;
29      }
30  }
View Code

 

二叉查找樹BST

注意二叉查找樹不必定是平衡的,因此其查找複雜度不必定就是O(logn)

TreeMap是BST+Balanced。其刪除 插入 查找 min max ceil(x) floor(x)複雜度都是O(logn)

 

驗證二叉查找樹

注意必須是整個左子樹都比我小,整個右子樹都比我大。並不僅是左右子節點知足條件就行

 1 public boolean isValidBST(TreeNode root) {
 2         // write your code here
 3         if (root == null)
 4             return true;
 5         return isValidBSTHelp(root).isValid;
 6     }
 7     public ResultType isValidBSTHelp(TreeNode root) {
 8         ResultType right;
 9         ResultType left;
10         if (root.left == null && root.right == null) {
11             return new ResultType(true, root.val, root.val);
12         }
13         if (root.left == null) {
14             right = isValidBSTHelp(root.right);
15             if (right.isValid && root.val < right.min) {
16                 return new ResultType(true, root.val, right.max);
17             }
18             return new ResultType(false, 0, 0);
19         }
20         if (root.right == null) {
21             left = isValidBSTHelp(root.left);
22             if (left.isValid && root.val > left.max) {
23                 return new ResultType(true, left.min, root.val);
24             }
25             return new ResultType(false, 0, 0);
26         }
27         right = isValidBSTHelp(root.right);
28         left = isValidBSTHelp(root.left);
29         if (left.isValid && right.isValid) {
30             if (left.max < root.val && right.min > root.val) {
31                 return new ResultType(true, left.min, right.max);
32             }
33         }
34         return new ResultType(false, 0, 0);
35     }
36 class ResultType {
37      boolean isValid;
38      int min;
39      int max;
40      public ResultType(boolean isValid, int min, int max) {
41          this.isValid = isValid;
42          this.min = min;
43          this.max = max;
44      }
45  }
View Code

一樣的思路換一個方向,寫出來的代碼就漂亮許多。

 1  public boolean isValidBST(TreeNode root) {
 2         // write your code here
 3         return isValidBSTHelp(root).isValid;
 4     }
 5     public ResultType isValidBSTHelp(TreeNode root) {
 6         if (root == null) {
 7             return new ResultType(true, Integer.MAX_VALUE,Integer.MIN_VALUE);
 8         }
 9         ResultType left = isValidBSTHelp(root.left);
10         ResultType right = isValidBSTHelp(root.right);
11         if (!left.isValid || !right.isValid) {
12             return new ResultType(false, 0, 0);
13         }
14         if (root.left != null && root.val <= left.max 
15             || root.right !=null && root.val >= right.min) {
16             return new ResultType(false, 0, 0);
17         }
18         return new ResultType(true, 
19                 Math.min(root.val, left.min), 
20                 Math.max(root.val,right.max));
21     }
View Code

 

二叉查找樹迭代器

 1 public class BSTIterator {
 2     TreeNode root;
 3     Stack<TreeNode> stack;
 4     //@param root: The root of binary tree.
 5     public BSTIterator(TreeNode root) {
 6         // write your code here
 7         this.root = root;
 8         stack = new Stack<TreeNode>();
 9         TreeNode cur = root;
10         while(cur != null) {
11             stack.push(cur);
12             cur = cur.left;
13         }
14     }
15 
16     //@return: True if there has next node, or false
17     public boolean hasNext() {
18         // write your code here
19         return !stack.isEmpty();
20     }
21     
22     //@return: return next node
23     public TreeNode next() {
24         // write your code here
25         TreeNode cur = stack.pop();
26         TreeNode right = cur.right;
27         while (right != null) {
28             stack.push(right);
29             right = right.left;
30         }
31         return cur;
32     }
33 }
View Code

 

二叉樹的層次遍歷

 1 public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
 2         // write your code here
 3         ArrayList<ArrayList<Integer>> results = new ArrayList<>();
 4         ArrayList<Integer> list;
 5         if (root == null)
 6             return results;
 7         Queue<TreeNode> queue = new LinkedList<>();
 8         queue.offer(root);
 9         while (!queue.isEmpty()) {
10             int size = queue.size();
11             list = new ArrayList<>();
12             for (int i = 0; i< size; i++) {
13                 TreeNode cur = queue.peek();
14                 if (cur.left != null) {
15                     queue.offer(cur.left);
16                 }
17                 if (cur.right != null) {
18                     queue.offer(cur.right);
19                 }
20                 list.add(cur.val);
21                 queue.poll();
22             }
23             results.add(new ArrayList<>(list));
24         }
25         return results;
26     }
View Code

 

二叉樹查找樹中序後繼 ***

 1 public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
 2         // write your code here
 3         if (root == null || p == null) {
 4             return null;
 5         }
 6         if (root.val == p.val) {
 7             TreeNode right = root.right;
 8             while (right != null && right.left != null) {
 9                 right = right.left;
10             }
11             return right;
12         }
13         if (root.val > p.val) {
14             TreeNode left = inorderSuccessor(root.left, p);
15             if (left == null) {
16                 return root;
17             }
18             return left;
19         }
20         return inorderSuccessor(root.right, p);
21     }
View Code

 

二叉樹的路徑和

 

給定一個二叉樹,找出全部路徑中各節點相加總和等於給定 目標值 的路徑。

 

一個有效的路徑,指的是從根節點到葉節點的路徑。

 1 public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) {
 2         // Write your code here
 3         List<List<Integer>> results = new ArrayList<List<Integer>>();
 4         if (root == null) {
 5             return results;
 6         }
 7         help(results, new ArrayList<Integer>(), root, target);
 8         return results;
 9     }
10     public void help(List<List<Integer>> results, List<Integer> cur, 
11                      TreeNode root, int target) {
12         cur.add(root.val);
13         if (target == root.val && root.left == null && root.right == null) {
14             results.add(new ArrayList<Integer>(cur));
15         }
16         if (root.left != null) {
17             help(results, cur, root.left, target - root.val);
18         }
19         if (root.right != null) {
20             help(results, cur, root.right, target - root.val);
21         }
22         cur.remove(cur.size() - 1);
23     }
View Code

 

扭轉後等價的二叉樹

檢查兩棵二叉樹是否在通過若干次扭轉後能夠等價。扭轉的定義是,交換任意節點的左右子樹。等價的定義是,兩棵二叉樹必須爲相同的結構,而且對應位置上的節點的值要相等。

 1  public boolean isTweakedIdentical(TreeNode a, TreeNode b) {
 2         // Write your code here
 3         if (a == null && b == null) {
 4             return true;
 5         }
 6         if (a == null || b == null || a.val != b.val) {
 7             return false;
 8         }
 9         return isTweakedIdentical(a.left, b.left) 
10                 && isTweakedIdentical(a.right, b.right)
11                 ||
12                 (  isTweakedIdentical(a.left, b.right) 
13                 && isTweakedIdentical(a.right, b.left));
14     }
View Code

 對稱二叉樹

 1 public boolean isSymmetric(TreeNode root) {
 2         // Write your code here
 3         if (root == null) {
 4             return true;
 5         }
 6         return help(root.left, root.right);
 7     }
 8     public boolean help(TreeNode left, TreeNode right) {
 9         if(left == null && right == null) {
10             return true;
11         }
12         if (left == null || right == null || left.val != right.val) {
13             return false;
14         }
15         return help(left.left, right.right) 
16             && help(left.right, right.left);
17     }
View Code

 

徹底二叉樹

只有最後一層能夠不滿,最後一層從左到右排列。因此可使用層序遍歷,遍歷同層的時候看看是否有左邊空了,右邊不空的狀況。遍歷下一層的時候看看是否有上層不滿的狀況。

以前兩種思路:第一種看是否全部節點的左子樹節點數大於等於右子樹節點數,這是不對的,例如:1 2 3 4 # 5 

       另一種看葉子節點數目是否是全部節點數目的上限一半也是有問題的,例如: 1 2 3 #  # 4

 1 public boolean isComplete(TreeNode root) {
 2         // Write your code here
 3         Queue<TreeNode> queue = new LinkedList<>();
 4         if (root == null) {
 5             return true;
 6         }
 7         queue.offer(root);
 8         int num = 1;
 9         while (!queue.isEmpty()) {
10             int size = queue.size();
11             if (num != size && queue.peek().left!=null) {
12                 return false;
13             }
14             num = num * 2;
15             boolean flag = true;
16             for (int i = 0; i < size; i++) {
17                 TreeNode cur = queue.poll();
18                 if (!flag && (cur.left != null || cur.right != null)) {
19                     return false;
20                 }
21                 if (cur.left != null) {
22                     queue.offer(cur.left);
23                     if (cur.right != null) {
24                         queue.offer(cur.right);
25                     }
26                     else {
27                         flag = false;
28                     }
29                 }
30                 else {
31                     if (cur.right != null) {
32                         return false;
33                     }
34                     flag = false;
35                 }
36             }
37         }
38         return true;
39     }
View Code

前序遍歷和中序遍歷樹構造二叉樹

 1 public TreeNode buildTree(int[] preorder, int[] inorder) {
 2         // write your code here
 3         if (preorder == null || preorder.length == 0 
 4             || inorder == null || preorder.length != inorder.length) {
 5                 return null;
 6         }
 7         Map<Integer,Integer> map = new HashMap<Integer, Integer>();
 8         for (int i = 0; i < inorder.length; i++) {
 9             map.put(inorder[i], i);
10         }
11         return buildHelp(preorder, 0, preorder.length - 1,
12                          inorder, 0, inorder.length - 1, map);
13     }
14     public TreeNode buildHelp(int[] preorder, int pre_begin, int pre_end,
15                               int[] inorder, int in_begin, int in_end, 
16                               Map<Integer,Integer> map) {
17         if (pre_begin > pre_end) {
18             return null;
19         }
20         if (pre_begin == pre_end) {
21             return new TreeNode(preorder[pre_begin]);
22         }     
23         TreeNode root = new TreeNode(preorder[pre_begin]);
24         int index = map.get(preorder[pre_begin]);
25         root.left = buildHelp(preorder, pre_begin + 1, pre_begin + index - in_begin,
26                             inorder, in_begin, index - 1, map);
27         root.right = buildHelp(preorder, pre_begin + index - in_begin + 1, pre_end,
28                             inorder, index + 1, in_end, map);
29         return root;
30     }
View Code

 

中序遍歷和後序遍歷樹構造二叉樹

 1 public TreeNode buildTree(int[] inorder, int[] postorder) {
 2         // write your code here
 3         if (inorder == null || inorder.length == 0 
 4         || postorder == null || postorder.length != inorder.length) {
 5             return null;
 6         }
 7         Map<Integer,Integer> map = new HashMap<Integer,Integer>();
 8         for (int i = 0; i < inorder.length; i++) {
 9             map.put(inorder[i],i);
10         }
11         return buildHelp(inorder, 0, inorder.length - 1,
12                 postorder, 0, postorder.length - 1, map);
13     }
14     public TreeNode buildHelp(int[] inorder, int in_start, int in_end,
15                               int[] postorder, int post_start, int post_end,
16                               Map<Integer,Integer> map) {
17         if (in_start > in_end) {
18             return null;
19         }               
20         if (in_start == in_end) {
21             return new TreeNode(postorder[post_end]);
22         }
23         TreeNode root = new TreeNode(postorder[post_end]);
24         int index = map.get(root.val);
25         root.left = buildHelp(inorder, in_start, index - 1,
26                     postorder, post_start, post_start + index - 1 - in_start,
27                     map);
28         root.right = buildHelp(inorder, index + 1, in_end,
29                     postorder, post_start + index - in_start, post_end - 1,
30                     map);
31         return root;
32     }
View Code

 

二叉查找樹中搜索區間

給定兩個值 k1 和 k2(k1 < k2)和一個二叉查找樹的根節點。

找到樹中全部值在 k1 到 k2 範圍內的節點。

即打印全部x (k1 <= x <= k2) 其中 x 是二叉查找樹的中的節點值。

返回全部升序的節點值。

 1 public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) {
 2         // write your code here
 3         ArrayList<Integer> res = new ArrayList<Integer>();
 4         helper(root, k1, k2, res);
 5         return res;
 6     }
 7     public void helper(TreeNode root, int k1, int k2, ArrayList<Integer> res) {
 8         if (root == null) {
 9             return ;
10         }
11         if (root.val > k1) {
12             helper(root.left, k1, k2, res);
13         }
14         if (root.val >= k1 && root.val <= k2) {
15             res.add(root.val);
16         }
17         if (root.val < k2) {
18             helper(root.right, k1, k2, res);
19         }
20     }
View Code

 

 二叉樹的序列化和反序列化

 使用前序遍歷比層序遍從來得簡單直觀的多。

 1  public String serialize(TreeNode root) {
 2         // write your code here
 3         StringBuilder sb = new StringBuilder();
 4         bulidString(root, sb);
 5         return sb.toString();
 6     }
 7     public void bulidString(TreeNode root, StringBuilder sb) {
 8         if (root == null) {
 9             sb.append("#,");
10         }
11         else {
12             sb.append(root.val).append(",");
13             bulidString(root.left, sb);
14             bulidString(root.right, sb);
15         }
16     }
17     public TreeNode deserialize(String data) {
18         // write your code here
19         Queue<String> queue = new LinkedList<String>();
20         queue.addAll(Arrays.asList(data.split(",")));
21         return buildTree(queue);
22     }
23     public TreeNode buildTree(Queue<String> queue) {
24         String cur = queue.poll();
25         if (cur.equals("#")) {
26             return null;
27         } 
28         else {
29             TreeNode root = new TreeNode(Integer.valueOf(cur));
30             root.left = buildTree(queue);
31             root.right = buildTree(queue);
32             return root;
33         }
34     }
View Code

 

刪除二叉查找樹的節點***

給定一棵具備不一樣節點值的二叉查找樹,刪除樹中與給定值相同的節點。若是樹中沒有相同值的節點,就不作任何處理。你應該保證處理以後的樹還是二叉查找樹。

 eeNode parent = findNode(dummy, root, value);//值爲value的節點的父節點

 1 public TreeNode deleteNode(TreeNode root, int key) {
 2        TreeNode dummy = new TreeNode(0);
 3        dummy.left = root;
 4        TreeNode parent = findNode(dummy, root, key);
 5        TreeNode node = null;
 6        if (parent.left != null && parent.left.val == key) {
 7            node = parent.left;
 8        } else if (parent.right != null && parent.right.val == key) {
 9            node = parent.right;
10        } else {
11            return dummy.left;
12        }
13        deleteNode(parent, node);
14        return dummy.left;
15         
16     }
17     public void deleteNode(TreeNode parent, TreeNode node) {
18         if (node.right == null) {
19             if (parent.left == node) {
20                 parent.left = node.left;
21                 return;
22             } else {
23                 parent.right = node.left;
24                 return;
25             }
26         }
27         TreeNode father = node;
28         TreeNode rightMin = node.right;
29         while (rightMin.left != null) {
30             father = rightMin;
31             rightMin = rightMin.left;
32         }
33         if (father.left == rightMin) {
34             father.left = rightMin.right;
35         } else {
36             father.right = rightMin.right;
37         }
38         if (parent.left == node) {
39             parent.left = rightMin;    
40         } else {
41             parent.right = rightMin;
42         }
43         rightMin.left = node.left;
44         rightMin.right = node.right;
45     }
46     public TreeNode findNode(TreeNode parent, TreeNode root, int key) {
47         if (root == null) {
48             return parent;
49         }
50         if (root.val == key) {
51             return parent;
52         }
53         if (root.val < key) {
54             return findNode(root, root.right, key);
55         } else {
56             return findNode(root, root.left, key);
57         }
58     }
View Code

 

Kth Smallest Element in a BST

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.

方法一:中序遍歷以後直接取得

 1 def kthSmallest(self, root, k):
 2         """
 3         :type root: TreeNode
 4         :type k: int
 5         :rtype: int
 6         """
 7         if not root:
 8             return -1
 9         res=[]
10         self.inorderTranverse(root, res)
11         return res[k - 1]
12     def inorderTranverse(self, root, res):
13         if root.left:
14             self.inorderTranverse(root.left, res)
15         res.append(root.val)
16         if root.right:
17             self.inorderTranverse(root.right, res)
View Code

 

方法二:中序遍歷到第k個元素返回

 1  def kthSmallest(self, root, k):
 2         """
 3         :type root: TreeNode
 4         :type k: int
 5         :rtype: int
 6         """
 7         if not root:
 8             return -1
 9         num = 0
10         stack = []
11         while root or len(stack)!=0:
12             while root:
13                 stack.append(root)
14                 root = root.left
15             node = stack.pop()
16             num += 1
17             if num == k:
18                 return node.val
19             if node.right:
20                 root = node.right
21         return -1
View Code

 

方法三:二分查找

 1 def kthSmallest(self, root, k):
 2         """
 3         :type root: TreeNode
 4         :type k: int
 5         :rtype: int
 6         """
 7         if not root:
 8             return -1
 9         leftNum = self.getNodeNum(root.left)
10         if leftNum >= k:
11             return self.kthSmallest(root.left,k)
12         elif leftNum < k - 1:
13             return self.kthSmallest(root.right, k - leftNum - 1)
14         else:
15             return root.val
16     def getNodeNum(self, root):
17         if not root:
18             return 0
19         else:
20             return self.getNodeNum(root.left) + self.getNodeNum(root.right) + 1
View Code

 

Binary Tree Serialization

 1 public String serialize(TreeNode root) {
 2         // write your code here
 3         StringBuilder sb = new StringBuilder();
 4         return buildString(root, sb);
 5     }
 6     
 7     private String buildString(TreeNode root, StringBuilder sb) {
 8         if (root == null) {
 9             sb.append("#,");
10             return sb.toString();
11         }
12         sb.append(root.val + ",");
13         buildString(root.left, sb);
14         buildString(root.right, sb);
15         return sb.toString();
16     }
17 public TreeNode deserialize(String data) {
18         // write your code here
19         if (data == null || data.length() == 0) {
20             return null;
21         }
22         String[] strs = data.split(",");
23         Queue<String> queue = new LinkedList<String>();
24         queue.addAll(Arrays.asList(strs));
25         return buildNode(queue);
26     }
27     
28     private TreeNode buildNode(Queue<String> queue) {
29         String cur = queue.poll();
30         if (cur.equals("#")) {
31             return null;
32         } else {
33             TreeNode root = new TreeNode(Integer.valueOf(cur));
34             root.left = buildNode(queue);
35             root.right = buildNode(queue);
36             return  root;
37         }
38     }
View Code
相關文章
相關標籤/搜索