LeetCode Hot 100 No.236 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

LeetCode Hot 100 No.236 二叉树的最近公共祖先_第1张图片

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:
LeetCode Hot 100 No.236 二叉树的最近公共祖先_第2张图片

输入: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; 
    }
}

你可能感兴趣的:(LeetCode,Hot,100,leetcode,二叉树,数据结构,算法)