1、数据结构:树节点 TreeNode
2、递归:递归遍历树,当节点为null时返回null,当节点为目标节点p,q 时,返回对应的p,q。
二叉树中目标节点p,q 的位置存在以下几种可能(1)p,q 分别为某一棵子树的左右节点上。(2)p,q同在一颗左子树中。(3)p,q同在一颗右子树中。对各个情况分别讨论,得到:
情况(1):left,right 分别返回 p,q 节点,则返回当前节点。
情况(2):left 返回 p 节点,right返回 null 节点,返回 p 节点。
情况(3):left 返回 q 节点,right返回 null 节点,返回 q 节点。
优化思路:
1)当left或者right既不为null,也不是p或者q中的任意一个,那么仅有一种情况,当前的这个left或者right就是所求的最近公共祖先,可以停止相关的遍历,直接返回。
2)由于递归返回的情况仅有以下几种(p和q,p和nil,q和nil,最近公共祖先和nil,所以当检测到left,right不为空时,直接返回当前节点即可
Go
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
var lowest func(r *TreeNode) *TreeNode
lowest=func(r *TreeNode) *TreeNode{
if r==nil || r==p || r==q{ return r }
left:=lowest(r.Left)
if left!=nil && left!=p && left!=q{ return left }
right:=lowest(r.Right)
if left!=nil && right!=nil{ return r }
if left!=nil{ return left }else{ return right }
}
return lowest(root)
}
Java
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null || root==p || root==q) return root;
TreeNode l=lowestCommonAncestor(root.left, p, q);
if(l!=null && l!=p && l!=q) return l;
TreeNode r=lowestCommonAncestor(root.right, p, q);
if(l!=null && r!=null) return root;
return l!=null ? l:r;
}
}
注意:看到二叉树,首先想到递归的解法,对于递归要将其分情况讨论,遍历搜索过程中的所有可能情况。