给定一棵二叉树和两个节点,这两个节点的最近公共祖先。
方法一:使用递归的方法,计算左右子树和当前子树中包含目标节点的个数。如果当前子树包含的节点数为2,而左右节点都小于2,那么当前节点就是两个目标的最近公共祖先。
TreeNode LCA = null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
numOfTargets(root, p, q);
return LCA;
}
public int numOfTargets(TreeNode root, TreeNode p, TreeNode q){
if(root == null)
return 0;
int ln = numOfTargets(root.left, p, q);
int rn = numOfTargets(root.right, p, q);
int num = ln + rn;
if(root == p) num += 1; //不能用if(root == p || root == q),因为可能p和q会是同一个节点
if(root == q) num += 1;
if(ln < 2 && rn < 2 && num == 2)
LCA = root;
return num;
}
方法二:利用公共祖先在同一条路径上这个性质,当找到一个节点时即当前节点。对于任意节点,如果左子树不含有目标,则返回右子树的结果,如果右子树不含有目标,则返回左子树的结果。如果两个子树都含有目标,则返回当前节点。这样的话,如果是LCA,那么其他子树都不会含有目标,LCA就会沿着路径一直返回到root。如果只是含有一个节点,当遇到另一个含有目标的子树时,更新返回值,然后一直返回到root。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root; //找到一个节点或者到达null,返回当前节点或null
TreeNode left = lowestCommonAncestor(root.left, p, q); //左子树中是否有目标
TreeNode right = lowestCommonAncestor(root.right, p, q); //右子树中是否有目标
if(left != null && right != null) return root; //如果左右子树分别有目标,当前节点就是LCA。此时其他分支都会返回null,而此节点会一直沿着路径传递到root
if(left == null) return right; //左子树中不含有目标,返回右子树的结果
else return left; //
}