给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
思路:
第一种求解方式:
如果二叉树采用双亲表示法或者孩子双亲表示法,就可以把问题转换为链表相交求交点
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(null==root||p==null||q==null){
return null;
}
//获取p和q在root中的路径
Stack<TreeNode> pPath=new Stack<>();
Stack<TreeNode> qPath=new Stack<>();
getNodePath(root,p,pPath);
getNodePath(root,q,qPath);
//两个路径对应的栈:1、应该让节点个数多的栈先出栈,直到节点个数相同
// 2、依次比较栈顶的元素
// a、相等---->即最近公共祖先节点
// b、不相等---->两个栈同时出,然后继续执行2步骤
//(可以画图借助理解)
int sizep=pPath.size();
int sizeq=qPath.size();
while(sizep != 0 && sizeq != 0){
if(sizep>sizeq){
pPath.pop();
sizep--;
}else if(sizep<sizeq){
qPath.pop();
sizeq--;
}else{
if(pPath.peek() == qPath.peek()){
return pPath.peek();
}else{
pPath.pop();
qPath.pop();
sizep--;
sizeq--;
}
}
}
return null;
}
//获取节点在root中的路径
private boolean getNodePath(TreeNode root,TreeNode node,Stack<TreeNode> sPath){
if(null==root){
return false;
}
sPath.push(root);
if(root==node){
return true;
}
//递归到root的左子树||右子树中找路径
if(getNodePath(root.left,node,sPath)||getNodePath(root.right,node,sPath)){
return true;
}
sPath.pop();
return false;
}
}
第二种求解方式:
假设二叉树是一颗二叉搜索树(二叉排序树)
步骤:
1、p和q只要有一个节点是根节点 || p在左子树中 && q在右子树中 || p在右子树中 && q在左子树中,则最近的公共祖先一定是根节点
2、p和q都在根节点的左子树中—则递归到根节点的左子树中求p和q的最近公共祖先
3、p和q都在根节点的右子树中—则递归到根节点的右子树中求p和q的最近公共祖先
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null|| p ==null|| q == null){
return null;
}
//如果有一个节点在根的位置,则最近公共祖先一定是根节点
if(root==p||root==q){
return root;
}
//检测p和q在root子树中的情况
boolean isPInLeft = false;
boolean isPInRight = false;
boolean isQInLeft = false;
boolean isQInRight = false;
//检测p在root子树中的情况
if(isNodeInTree(root.left,p)){
isPInLeft = true;
isPInRight = false;
}else{
isPInLeft = false;
isPInRight = true;
}
//检测q在root子树中的情况
if(isNodeInTree(root.left,q)){
isQInLeft=true;
isQInRight=false;
}else{
isQInLeft=false;
isQInRight=true;
}
//p和q分别在root的左右子树中
if(isPInLeft && isQInRight || isPInRight && isQInLeft){
return root;
}else if(isPInLeft && isQInLeft){
return lowestCommonAncestor(root.left,p,q);
}else{
return lowestCommonAncestor(root.right,p,q);
}
}
//检测一个节点是否在二叉树中
private boolean isNodeInTree(TreeNode root,TreeNode node){
if(null==root){
return false;
}
if(root==node){
return true;
}
if(isNodeInTree(root.left,node)||isNodeInTree(root.right,node)){
return true;
}
return false;
}
}