【剑指Offer】面试题68:树中两个节点的最低公共祖先

【剑指Offer】面试题68:树中两个节点的最低公共祖先_第1张图片

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 面试题68:树中两个节点的最低公共祖先。leetcode Hot100 236题,中等
 * 题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
 * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,
 * 最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
 *
 * @author
 * @create 2021-05-06 13:41
 */
public class Solution68 {
     
    public static void main(String[] args) {
     
        TreeNode root = new TreeNode(1);
        TreeNode node2 = new TreeNode(2);
        TreeNode node3 = new TreeNode(3);
        TreeNode node4 = new TreeNode(4);
        TreeNode node5 = new TreeNode(5);
        TreeNode node6 = new TreeNode(6);
        TreeNode node7 = new TreeNode(7);
        TreeNode node8 = new TreeNode(8);
        TreeNode node9 = new TreeNode(9);
        TreeNode node10 = new TreeNode(10);
        TreeNode node11 = new TreeNode(11);
        TreeNode node12 = new TreeNode(12);

        root.left = node2;
        root.right = node3;
        node2.left = node4;
        node2.right = node5;
        node4.left = node8;
        node4.right = node9;
        node5.left = node10;
        node5.right = node11;
        node3.left = node6;
        node3.right = node7;
        node6.left = node12;

        Solution68 solu = new Solution68();
        TreeNode ancestor = solu.lowestCommonAncestorTwo(root, node9, node11);
        System.out.println(ancestor.val);
    }




    /**
     * 方法一:递归
     * 时间复杂度:O(N),其中N是二叉树的节点数。二叉树的所有节点有且只会被访问一次,因此时间复杂度为 O(N)。
     * 空间复杂度:O(N),其中N是二叉树的节点数。递归调用的栈深度取决于二叉树的高度,二叉树最坏情况下为一条链,
     * 此时高度为 N,因此空间复杂度为 O(N)。
     * @param root
     * @param p
     * @param q
     * @return
     */
    private TreeNode ans;
    public boolean dfs(TreeNode root, TreeNode p, TreeNode q){
     
        if (root == null){
     
            //退出递归
            return false;
        }
        //向左递归
        boolean lson = dfs(root.left, p ,q);
        //向右递归
        boolean rson = dfs(root.right, p, q);
        //判断条件:
        //①左子树和右子树同时包含两个节点,(lson && rson)左子树和右子树均包含p节点或q节点,
        //      如果左子树包含的是p节点,
        //      那么右子树只能包含q节点,反之亦然,因为p节点和q节点都是不同且唯一的节点,
        //      因此如果满足这个判断条件即可说明 x 就是我们要找的最近公共祖先。
        //②或者当前节点是要查找的节点并且该节点的左子树或者右子树包含另一个要查找的节点.
        //      这个判断条件即是考虑了x恰好是p节点或q节点且它的左子树或右子树有一个包含了另一个节点的情况,
        //      因此如果满足这个判断条件亦可说明x就是我们要找的最近公共祖先。
        if ((lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson))){
     
            ans = root;
        }
        return lson || rson || (root.val == p.val || root.val == q.val);
    }

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
     
        dfs(root, p, q);
        return ans;
    }

    /**
     * 方法二:存储父节点
     * 从根节点开始遍历整棵二叉树,用哈希表记录每个节点的父节点指针。
     * 从p节点开始不断往它的祖先移动,并用数据结构记录已经访问过的祖先节点。
     * 同样,我们再从q节点开始不断往它的祖先移动,如果有祖先已经被访问过,
     * 即意味着这是p和q的深度最深的公共祖先,即LCA节点。
     * 
     * 时间复杂度:O(N),其中N是二叉树的节点数。二叉树的所有节点有且只会被访问一次,
     *      从p和q节点往上跳经过的祖先节点个数不会超过 N,因此总的时间复杂度为 O(N)。
     *
     * 空间复杂度:O(N),其中N是二叉树的节点数。递归调用的栈深度取决于二叉树的高度,
     *      二叉树最坏情况下为一条链,此时高度为N,因此空间复杂度为O(N),
     *      哈希表存储每个节点的父节点也需要 O(N)的空间复杂度,因此最后总的空间复杂度为 O(N)。
     ** @param root
     * @return
     */
    Map<Integer, TreeNode> parent = new HashMap<>();
    Set<Integer> visited = new HashSet<>();

    public void dfsTwo(TreeNode root){
     
        if (root.left != null){
     
            parent.put(root.left.val, root);
            dfsTwo(root.left);
        }
        if (root.right != null){
     
            parent.put(root.right.val, root);
            dfsTwo(root.right);
        }
    }

    public TreeNode lowestCommonAncestorTwo(TreeNode root, TreeNode p, TreeNode q){
     
        dfsTwo(root);
        while (p != null){
     
            visited.add(p.val);
            p = parent.get(p.val);//p.val为根节点时返回null,退出循环
        }
        while (q != null){
     
            if (visited.contains(q.val)){
     
                return q;
            }
            q = parent.get(q.val);
        }
        return null;
    }
}

你可能感兴趣的:(Java,剑指offer,二叉树)