公共祖先--binary tree
找binary tree中两个node第一个公共祖先。注意不一定是BST
想法:p,q都在左子树,就branch left。如果都在right,就branch right。如果不在same side,就返回first common ancestor
所以主要是在left subtree和right subtree中找两个node
Solution1 : from cc150
由于covers函数被调用2n nodes(n for left side and n nodes for right side).之后如果在同一边,会继续递归search,还需要check covers,调用2n / 2次,然后 2n/4次。。。
time: O(2n) + O(2n/2) + O(2n / 4) + ... = O(N)
1 public static TreeNode commonAncestor2(TreeNode root, TreeNode p, TreeNode q) { 2 if (!covers(root, p) || !covers(root, q)) { // Error check - one node is not in tree 3 return null; 4 } 5 return helper(root, p, q); 6 } 7 private static TreeNode helper(TreeNode root, TreeNode p, TreeNode q){ 8 if(root == null) return null; 9 10 boolean is_p_on_left = covers(root.left, p); 11 boolean is_q_on_left = covers(root.left, q); 12 13 if(is_p_on_left != is_q_on_left){ 14 //nodes are on different side 15 return root; 16 } 17 TreeNode child_side = is_p_on_left ? root.left : root.right; 18 19 //search in subtree 20 return helper(child_side, p, q); 21 22 23 } 24 //check whether p is a descendent of root 25 private static boolean covers(TreeNode root, TreeNode p){ 26 if(root == null) return false; 27 28 if(root == p) return true; 29 30 return covers(root.left, p) || covers(root.right, p); 31 }
类似解法 http://xixiaogualu.blogspot.com/2013/09/lowest-common-ancestor-of-binary-tree.html
top - bottom自顶向下:
public static TreeNode LCA1(TreeNode root,TreeNode n1,TreeNode n2){ if(exist(root.left,n1) && (exist(root.left,n2))){ //find in left subtree return LCA1(root.left, n1, n2); } if(exist(root.right,n1)&&(exist(root.right,n2))){ return LCA1(root.right, n1, n2); } return root; } //find in subtree from root public static boolean exist(TreeNode root, TreeNode n){ if(root == n) return true; if(root == null) return false; return exist(root.left,n)||exist(root.right,n); }
Solution2:改进上面解法 from cc150
Bottom-up ,利用commonAncestor的返回值减少向下search次数,递归调用。
返回值可能的几种情况为:
commonAncestor(TreeNode root, TreeNode p, TreNode q)
return p, if root's subtree includes p (and not q)
return q, if root's subtree includes q( and not p)
return null, if neighter p nor q in root's subtree
else return common ancestor of p and q
1 public static TreeNode LCA(TreeNode root, TreeNode p, TreeNode q){ 2 if(root == null) return null; 3 if(root == p || root == q){ 4 5 return root; 6 } 7 8 //are child of root 9 if(p == root.left && q == root.right || p == root.right && q == root.left){ 10 return root; 11 } 12 13 //search in left and right subtree 14 TreeNode left = LCA(root.left, p, q); 15 TreeNode right = LCA(root.right, p, q); 16 17 if(left != null && right != null){ 18 //one is in left subtree and the other is in right 19 return root; 20 } 21 if(left != null){ 22 return left; 23 } 24 if(right != null){ 25 return right; 26 } 27 return null; 28 }
拓展: 如果可能p或者q为不在tree里的node,上面bottom up的方法就会产生问题
想法是如果利用这个返回值来区分两种情况:
case 1: p is a child of q ( or, q is a child of p)
case 2: p is in the tree and q is not( or, q is in the tree and p is not)
both cases would return p. but case 2 actually is not ancestor, should be null.
借助辅助类
用boolean isAncestor标记case2
class Result{ public TreeNode node; public boolean isAncestor; public Result(TreeNode n, boolean isAnc){ node = n; isAncestor = isAnc; } }
public static TreeNode commonAncestor3(TreeNode root, TreeNode p, TreeNode q) { Result res = helper(root, p, q); if(res.isAncestor){ return res.node; } return null; }
1 private static Result helper(TreeNode root, TreeNode p, TreeNode q){ 2 if(root == null){ 3 return new Result(null, false); 4 } 5 if(root == p && root == q){ 6 return new Result(root, true); 7 } 8 9 Result left = helper(root.left, p, q); 10 if(left.isAncestor){ 11 return left; 12 } 13 Result right = helper(root.right, p,q); 14 if(right.isAncestor){ 15 return right; 16 } 17 //find common ancestor 18 if(left.node != null && right.node != null){ 19 return new Result(root, true); 20 }else if(root == p || root == q){ 21 /* If we’re currently at p or q, and we also found one of those 22 nodes in a subtree, then this is truly an ancestor and the 23 flag should be true. */ 24 boolean isAncestor = left.node != null || right.node != null; 25 return new Result(root, isAncestor); 26 }else{ 27 // 28 return new Result(left.node != null ? left.node : right.node, false); 29 } 30 }
with link to parent
这样只需要trace p and q's parents up until intersect. 因为p,q可能不同level,例如q在p子树中。所以要用hashtable来记录已经trace的node。
或者先move到同一个level,然后同时move up两个指针,判断是否相同,返回第一个相同时的node