题目
方法一:递归
p和q的最近公共节点r满足要求:r的左节点为p的祖先,右节点为q的祖先。或者r的右节点为q的祖先,左节点为p的祖先。
因此构建一个递归函数,如果参数root的左右节点满足以上条件,这个root即为答案。否则,root如果是p的祖先则返回p,如果是q的祖先则返回q,再则返回null
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null)
return null;
if(root == p || root == q)
return root;
TreeNode left = lowestCommonAncestor(root.left , p , q);
TreeNode right = lowestCommonAncestor(root.right , p , q);
if(left == null && right == null)
return null;
if(left != null && right != null) // 左右子树都不是null,肯定是左右各是pq的祖先,则root就是最近公共祖先
return root;
return left == null ? right : left;
}
- 时间复杂度:需要遍历一遍树为O(n)
- 空间复杂度:递归栈空间,取决树的高度,需要O(logn)
方法二:非递归
可以用一个map来记录每个节点的父节点,再找pq的第一个公共祖先;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
Map<TreeNode , TreeNode> fMap = new HashMap<>();
Deque<TreeNode> deque = new ArrayDeque<>();
deque.addLast(root);
while(!deque.isEmpty()){
int size = deque.size();
for(int i = 0; i < size; i++){
TreeNode peek = deque.poll();
if(peek.left != null){
deque.addLast(peek.left);
fMap.put(peek.left , peek);
}
if(peek.right != null){
deque.addLast(peek.right);
fMap.put(peek.right , peek);
}
}
}
Set<TreeNode> visited = new HashSet<>();
visited.add(p);
TreeNode tmp = p;
while(tmp != root){
tmp = fMap.get(tmp);
visited.add(tmp);
}
visited.add(tmp);
tmp = q;
while(!visited.contains(tmp))
tmp = fMap.get(tmp);
return tmp;
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)