题目
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
题干:
一棵树T有两个节点pq说明pq就是树的节点不存在pq不存在,除非这棵树不存在
解1-递归
- 递归终止条件:
- root为空直接返回null
- p,q为root直接返回root
- 递归
- 递归左子节点返回值left
- 递归右子节点返回值right
- 返回值left和right分为4种情况
- left和right均为null,说明root的左右子树均不包括p,q返回null
- left空right不空说明pq不在左子树返回right
- left不空right空说明pq不在右子树返回left
- left和right均不为空说明pq分布在root的异侧(分别在左右子树)那么只能root为公共祖先
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null||p==root||q==root){
return root;
}
TreeNode left=lowestCommonAncestor(root.left,p,q);
TreeNode right=lowestCommonAncestor(root.right,p,q);
//left和right均为空
//可以省略此条件,因为p,q肯定存在,除非树不存在,题干就是一棵树有p,q两节点
if(left==null&&right==null){
return null;
}
//left空right不空
if(left==null){
return right;
}
//left不空right空
if(right==null){
return left;
}
//left和right均不为空-一个在左子树一个在右子树
return root;
}
}
复杂度
时间复杂度O(n):n为二叉树的节点个数
空间复杂度O(n):退化为一条链表递归栈需要n的空间
解2
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//有一个在根说明公共祖先就是根
if(p==root||q==root){
return root;
}
//搜索节点的位置
boolean pLeft=search(root.left,p);
boolean qLeft=search(root.left,q);
//都在左子树
if(pLeft&&qLeft){
return lowestCommonAncestor(root.left,p,q);
}
//都在右子树
if(!pLeft&&!qLeft){
return lowestCommonAncestor(root.right,p,q);
}
//一个在左一个在右,那公共祖先只能是root
return root;
}
private boolean search(TreeNode root,TreeNode t){
if(root==null){
return false;
}
if(root==t){
return true;
}
if(search(root.left,t)){
return true;
}
return search(root.right,t);
}
}
解3-BFS
- map保存p和p的父节点(迭代)
- 用集合存储p的祖先节点
- 在p的祖先集合中是否包含q和q的祖先节点
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
Deque<TreeNode> queue=new LinkedList<>();
//记录每个节点的父节点
Map<TreeNode,TreeNode> map=new HashMap<>();
//根节点没有父节点
queue.add(root);
map.put(root,null);
//p q都找到就退出循序
while(!map.containsKey(p)||!map.containsKey(q)){
TreeNode node=queue.remove();
if(node.left!=null){
queue.add(node.left);
map.put(node.left,node);
}
if(node.right!=null){
queue.add(node.right);
map.put(node.right,node);
}
}
/*
Set<TreeNode> set=new HashSet<>();
//将p的祖先节点保存起来
while(p!=null){
set.add(p);
p=map.get(p);
}
//在p的祖先节点中找是否存在q或q的祖先节点
while(!set.contains(q)){
q=map.get(q);
}
*/
List<TreeNode> list=new ArrayList<>();
//将p到root一条线串起来
while(p!=null){
list.add(p);
p=map.get(p);
}
//p到root这条线中找q的祖先,循环一定会退出,,因为pq的公共祖先一定存在
/*
1. 存在非root的p和q的公共祖先就退出
2. root就是p和q的公共祖先
*/
while(!list.contains(q)){
q=map.get(q);
}
return q;
}
}
时间复杂度O(n) : 遍历所有节点
空间复杂度O(n): 退化为链表map存储所有节点