题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
五一第一天,上午起来完成一道题(可能一整个五一就做这一道题了)
二叉树的题目,基本上要么是广度优先,要么是深度优先。而这道题目要求我们给二叉树上任意深度的两个节点找到最近的祖先,那么显而易见的这道题需要使用的方法是深度优先。
深度优先,必将会调用自身进行递归,而且是对根节点的左右子节点都进行递归。
要找到给定节点p、q的根节点,就是要看否一个节点的左右子树是否存在与节点p,q等价的节点。换句话说,如果我们发现一个节点的左子结点刚好为p,而右子节点刚好为q,则该节点肯定是p、q的最近公共祖先。
所以我们从根节点开始递归向下遍历左右两侧的子树,当某一层的左子树等于p或q,将这个子树返回父节点(是告诉父节点它的儿子匹配成功了,而不是说将这个节点返回为题目要的答案),代表左子树下存在和p或q等价的节点;
同理当某一层的右子树等于p或q,将这个子树返回父节点(也是告诉父节点它的儿子匹配成功了,而不是说将这个节点返回为题目要的答案)),代表右子树下存在和p或q等价的节点;
当某节点的左子树和右子树都匹配成功返回了,就可以将此节点(刚刚匹配成功的左右子树的祖先)返回作为为题目要的答案。
在示例中,根节点的左子树是5,右子树是1,左右子树都匹配到了p,q,所以答案要直接返回根节点3。
我们定义 left、right两个变量分别递归左右子树,并在匹配到与p或q时,让整个函数直接返回父节点。
public TreeNode236 lowestCommonAncestor(TreeNode236 root, TreeNode236 p, TreeNode236 q) {
//节点匹配到了p/q,将这个节点返回给父亲
if(root == null || root == p || root == q){
return root;
}
TreeNode236 left = lowestCommonAncestor(root.left,p,q);
TreeNode236 right = lowestCommonAncestor(root.right,p,q);
//如果左子节点和有子节点都成功返回了,说明匹配成功,答案就是当前节点
if(left == p && right == q || left == q && right == q)
{
return root;
}
}
如果左子树下没有节点能匹配到p或者q,就从右子树的根作为起点开始看向下递归,不用看左子树了;
同理,如果右子树下没有节点能匹配到p或者q,就从左子树的根作为起点开始看向下递归,不用看右子树了;
public TreeNode236 lowestCommonAncestor(TreeNode236 root, TreeNode236 p, TreeNode236 q) {
if(root == null || root == p || root == q){
return root;
}
TreeNode236 left = lowestCommonAncestor(root.left,p,q);
TreeNode236 right = lowestCommonAncestor(root.right,p,q);
if(left == p && right == q || left == q && right == q)
{
return root;
}
if(left == null)
{
return right;
}
if(right == null)
{
return left;
}
return root;
}
下面这一段可以被省略,因为最终left和right都不为空时,下面这一层肯定是成立的。
if(left == p && right == q || left == q && right == q)
{
return root;
}
完整代码:
public TreeNode236 lowestCommonAncestor(TreeNode236 root, TreeNode236 p, TreeNode236 q) {
if(root == null || root == p || root == q){
return root;
}
TreeNode236 left = lowestCommonAncestor(root.left,p,q);
TreeNode236 right = lowestCommonAncestor(root.right,p,q);
//无需下面这一段
//if(left == p && right == q || left == q && right == q)
//{
// return root;
//}
if(left == null)
{
return right;
}
if(right == null)
{
return left;
}
return root;
}