题目描述:
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
样例:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
分析:
法1:分别找出根节点到两个节点的路径,则最后一个公共节点就是最低公共祖先。
- 利用一个栈来存储到节点的路径,栈中的最后一个节点肯定是目标节点。
- 如果某一个节点其左子树和右子树都不存在目标结点,则将该节点从栈中pop,继续遍历该节点的兄弟节点
- 然后从栈中的第一节点开始遍历,当对应节点不相同时结束遍历,最后一个相同的节点即为公共祖先,即当前结束节点的上一个节点。
法2:
- 如果查询节点分别位于该节点的左子树和右子树中,则祖先肯定是该节点;
- 如果在该节点的左子树中没有找到查询节点,则一定都位于该节点的右子树中,最低公共祖先一定位于右子树中。
- 如果在该节点的右子树中没有找到查询节点,则一定都位于该节点的左子树中,最低公共祖先一定位于左子树中。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
return null;
if(p==root&&q!=null||q==root&&p!=null) {
return root;
}
Stack<TreeNode> stack1=new Stack<>();
findpath(root,p,stack1,new TreeNode(0));
Stack<TreeNode> stack2=new Stack<>();
findpath(root,q,stack2,new TreeNode(0));
TreeNode common=null;
for(int i=0;i<Math.min(stack1.size(), stack2.size());i++) {
if(stack1.get(i)==stack2.get(i))
common=stack1.get(i);
else
break;
}
return common;
}
public void findpath(TreeNode root,TreeNode search,Stack<TreeNode> stack,TreeNode flag) {
if(root==null||flag.val==1)//保证了栈中最后一个节点肯定是search
return;
stack.push(root);
if(root.val==search.val) {
flag.val =1;
return;
}
findpath(root.left,search,stack,flag);
findpath(root.right,search,stack,flag);
if(flag.val!=1) {//说明以该节点为根节点的子树中不存在查找节点 !!!!
stack.pop();
}
}
public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
return null;
if(root==p||root==q) {
return root;
}
TreeNode left=lowestCommonAncestor2(root.left,p,q);
TreeNode right=lowestCommonAncestor2(root.right,p,q);
if(left!=null&&right!=null)
return root;//查询节点分别位于root节点的左右子树中
if(left==null)//查询节点均位于root节点的右子树中
return right;
if(right==null)//查询节点位于root节点的左子树中
return left;
return null;
}
相关题目:
二叉搜索树的最近公共祖先。
- 将查询节点的值和根节点的值进行比较,如果均大于根节点的值,则最低公共祖先一定位于右子树;如果均小于根节点的值,则最低公共祖先一定位于左子树;如果一个大于一个小于,则最低公共祖先为根节点。
普通树的最近公共祖先。
-
如果有指向父节点的指针,则每个叶节点到根节点都看以看做一个链表,因此转换为寻找两个链表的第一个公共节点。
-
如果没有指向父节点的指针,则利用两个栈分别保存从根节点到查找节点的路径,在保存的过程中如果某个节点的左子树和右子树均没有该节点则将该节点从栈中pop,确保栈中的最后一个节点是查找的节点。
-
然后从栈中的第一节点开始遍历,当对应节点不相同时结束遍历,最后一个相同的节点即为公共祖先