leetcode236. 二叉树的最近公共祖先(二叉树)

(基于评论区大佬的思路,该思路完爆官方的递归染色)

题目:

思路:

DFS遍历

用数组记录两个变量的父节点,然后找到公共父节点

class Solution {
    Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>();
    Set<Integer> visited = new HashSet<Integer>();

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

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        dfs(root);
        while (p != null) {
            visited.add(p.val);
            p = parent.get(p.val);
        }
        while (q != null) {
            if (visited.contains(q.val)) {
                return q;
            }
            q = parent.get(q.val);
        }
        return null;
    }
}

递归染色

由于大佬的代码思路和官方思路一致,只是极大的简化了代码,所以先来理解官方思路

官方题解的思路是对含有两个节点的路径进行标记,若一个节点满足公式((x == p || x == q) && (Flson || Frson)) || (Flson && Frson)则就是最近父节点

最近父节点仅有两种可能:

  1. p在最近父节点左/右子树,q在最近父节点右/左子树,两个节点不在同一子树上
  2. p/q的子树包含q/p(包括q/p就是最近父节点的情况)

上方公式即各自对应两种情况

(Flson && Frson)代表可能性(1),即左子树包含节点,右子树也包含节点,则当前节点就为最近父节点

((x == p || x == q) && (Flson || Frson)) 当前节点为最近父节点,同时左/右子树包含另一个节点,则当前节点也是最近父节点

官方代码:

class Solution {

    private TreeNode ans;

    public Solution() {
        this.ans = null;
    }

    private 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);
        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) {
        this.dfs(root, p, q);
        return this.ans;
    }
}

官方代码太过繁琐,即需要一个变量来记录答案,又需要用一个boolean类型来传递是否含有子节点.那么是否有一种办法传递一个变量来判断,最后的结果又是答案?

即包含目标节点的路径标记直接标记为目标节点,其余都为null,若左子树为null,则返回有可能包含目标节点的右子树,反之亦然.

仅有左右子树都被标记,则当前节点就是最近父节点,返回(可能性1)

最巧妙的是可能性(2),若一个目标节点在另一个目标节点的子树上,直接返回,就是答案

大佬代码:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q)
        {
            return root;
        }
        TreeNode leftRoot = lowestCommonAncestor(root.left,p,q);
        TreeNode rightRoot = lowestCommonAncestor(root.right,p,q);
        if(leftRoot == null) return rightRoot;
        if(rightRoot == null) return leftRoot;
        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值