给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。
最近公共祖先是两个节点的公共的祖先节点且具有最大深度。
样例
对于下面这棵二叉树
4
/ \
3 7
/ \
5 6
LCA(3, 5) = 4
LCA(5, 6) = 7
LCA(6, 7) = 7
注意事项
假设给出的两个节点都在树中存在
解题思路:
我们可以用深度优先搜索,从叶子节点向上,标记子树中出现目标节点的情况。如果子树中有目标节点,标记为那个目标节点,如果没有,标记为null。显然,如果左子树、右子树都有标记,说明就已经找到最小公共祖先了。如果在根节点为p的左右子树中找p、q的公共祖先,则必定是p本身。
换个角度,可以这么想:如果一个节点左子树有两个目标节点中的一个,右子树没有,那这个节点肯定不是最小公共祖先。如果一个节点右子树有两个目标节点中的一个,左子树没有,那这个节点肯定也不是最小公共祖先。只有一个节点正好左子树有,右子树也有的时候,才是最小公共祖先。
/**
* Definition of TreeNode:
* public class TreeNode {
* public int val;
* public TreeNode left, right;
* public TreeNode(int val) {
* this.val = val;
* this.left = this.right = null;
* }
* }
*/
public class Solution {
/*
* @param root: The root of the binary search tree.
* @param A: A TreeNode in a Binary.
* @param B: A TreeNode in a Binary.
* @return: Return the least common ancestor(LCA) of the two nodes.
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
// write your code here
//发现目标节点则通过返回值标记该子树发现了某个目标结点
if(root == null || root == A || root == B) return root;
//Divide
//查看左子树中是否有目标结点,没有为null
TreeNode left = lowestCommonAncestor(root.left, A, B);
//查看右子树是否有目标节点,没有为null
TreeNode right = lowestCommonAncestor(root.right, A, B);
//Conquer
//都不为空,说明左右子树都有目标结点,则公共祖先就是本身
if(left!=null && right!=null) return root;
//如果发现了目标节点,则继续向上标记为该目标节点
return left == null ? right : left;
}
}
复杂版:
/**
* Definition of TreeNode:
* public class TreeNode {
* public int val;
* public TreeNode left, right;
* public TreeNode(int val) {
* this.val = val;
* this.left = this.right = null;
* }
* }
*/
public class Solution {
/*
* @param root: The root of the binary search tree.
* @param A: A TreeNode in a Binary.
* @param B: A TreeNode in a Binary.
* @return: Return the least common ancestor(LCA) of the two nodes.
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
//若节点A与B分别在root的两边,则root本身为最近公共祖先
boolean both = (isIn(root.left, A) && isIn(root.right, B)) || (isIn(root.right, A) && isIn(root.left, B));
if(both)
return root;
//若节点A与B都在root的左侧,则继续去左边查找最近公共祖先
boolean left = isIn(root.left, A) && isIn(root.left, B);
if(left)
return lowestCommonAncestor(root.left, A, B);
//若节点A与B都在root的右侧,则继续去右边查找最近公共祖先
boolean right = isIn(root.right, A) && isIn(root.right, B);
if(right)
return lowestCommonAncestor(root.right, A, B);
//其他情况返回root,例如root==null,或者root==A,或者root==B
return root;
}
//在以root为根的二叉树中查找是否存在node节点
private boolean isIn(TreeNode root, TreeNode node){
if(root == null)
return false;
if(root.val == node.val)
return true;
return isIn(root.left, node) || isIn(root.right, node);
}
}