给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
方法一:
迭代法:这道题首先想到需要用后序遍历来做。通过栈来迭代的实现后序遍历操作。
当使用栈的时候,我们可以发现所有栈内元素都是栈顶元素的祖先节点(包括它自己),而且辈分关系还是一层一层递增的,(自己,父节点,爷爷节点。。。。。直到栈底)。所以我们每次循环到要pop栈顶节点的时候,如果栈顶节点等于p或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) {
TreeNode P = root;
LinkedList<TreeNode> stack = new LinkedList<>();
TreeNode last = null;
LinkedList<TreeNode> proot = new LinkedList<>();
LinkedList<TreeNode> qroot = new LinkedList<>();
while(P!=null||!stack.isEmpty())
{
if(P!=null)
{
stack.push(P);
P=P.left;
}
else
{
if(stack.peek().right!=null&&stack.peek().right!=last)
{
P = stack.peek().right;
}
else
{
if(stack.peek().val==p.val||stack.peek().val==q.val)
{
LinkedList<TreeNode> getroot = (stack.peek().val==p.val)?proot:qroot;
for(TreeNode i:stack)
{
getroot.add(i);
}
}
last = stack.pop();
}
}
}
for(TreeNode i:proot)
{
for(TreeNode j:qroot)
{
if(i.val==j.val)
return i;
}
}
return null;
}
}
方法二:
递归法:
最近公共祖先分为三种情况:
p和q分别在根节点的左右子树上,则最近公共祖先为根节点。
p和q都在根节点的左子树上,则最近公共祖先为左子树根节点。
p和q都在根节点的右子树上,则最近公共祖先为右子树根节点。
步骤:
1.递归查找左子树中是否有p或q节点,如果有,就返回该节点的引用,用left变量接收,如果没有就返回null。
2.递归查找右子树中是否有p或q节点,如果有,就返回该节点的引用,用right变量接收,如果没有就返回null。
如果左右子树中各存在p或q节点,left!=null,right!=null,则说明p和q分别在根节点的两侧,那么他们的公共祖先就是根节点,返回root。
如果左子树中p或q节点都不存在,即left==null,且p或q存在于右子树中,right!=null,则返回right。
如果右子树中p或q节点都不存在,即right==null,且p或q都存在于左子树中,left!=null,则返回left。
递归停止的条件是,当前根节点为p或q,就返回根节点。或者根节点为null,就返回null。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {//这个函数的作用是查找这棵树中p和q的最近公共祖先
if(root==null||root.val==p.val||root.val==q.val)
{return root;}
TreeNode isInLeft = lowestCommonAncestor(root.left,p,q);
TreeNode isInRight = lowestCommonAncestor(root.right,p,q);
if(isInLeft!=null&&isInRight!=null)
{return root;}
else if(isInLeft!=null&&isInRight==null)
{return isInLeft;}
else if(isInLeft==null&&isInRight!=null)
{return isInRight;}
else
return null;
}
}