236. Lowest-Common-Ancestor-of-a-Binary-Tree

difficulty: Medium

section pre{ background-color: #eee; border: 1px solid #ddd; padding:10px; border-radius: 5px; }

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]

Example 1:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output:
 3
Explanation: 
The LCA of nodes 5 and 1 is 3.

Example 2:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output:
 5
Explanation: 
The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

Note:

  • All of the nodes' values will be unique.

  • p and q are different and both values will exist in the binary tree.

Method One

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    // 观察发现, 最近的公共祖先有什么特征呢?
    // 当 p 和 q 在自己的左右子树各一个的时候,它是一个公共祖先。
    // 还有一种情况就是,它自己是 p 和 q 之一。而且它的左右子树有一个包含另一个。
    private TreeNode ancestor;
    private TreeNode p;
    private TreeNode q;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.ancestor = root;
        this.p = p;
        this.q = q;
        dfs(root);
        return ancestor;
    }
    
    public boolean dfs(TreeNode node) {
        if(node == null) {
            return false;
        }
        
        boolean isAtLeft = dfs(node.left);
        boolean isAtRight = dfs(node.right);
        
        if( (isAtLeft || isAtRight) && (node == this.p || node == this.q ) ) {
            this.ancestor = node;
            return true;
        }
        
        if( isAtLeft && isAtRight) {
            this.ancestor = node;
            return true;           
        }
        
        if( isAtLeft || isAtRight || node == this.p || node == this.q ) {
            return true;
        }
        return false;
    }
}
class Solution {
    // 这个解法特别好。
    // 我们在左边找,找不到的话说明在右边。
    // 我么在右边找,找不到的话说明在左边。
    // 实际上我们做的是什么?我们做的是 postOrder 搜索,找的 target 是 p 或者 q.
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q ) {
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if( left == null ) {
            return right;
        }
        if( right == null ) {
            return left;
        }
        return root;
    }
}

再想一个 iterative 的写法。 第一步,用 map 记录父节点。第二步,从某个节点出发找根,然后把一路上的节点都加到set1里。 第三步,从另一个节点出发找根,如果遇到set1存在某个节点,这个就是最低的公共祖先 lca 了。

1676 这个题不错的

class Solution {
    private Set<TreeNode> nodeSet;
    private TreeNode lca;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode[] nodes) {
        this.nodeSet = new HashSet<>();
        this.lca = null;
        for(TreeNode node : nodes){
            nodeSet.add(node);
        }
        numberOfNodesFound(root);
        return lca;
    }
    private int numberOfNodesFound(TreeNode node){
        if(node == null) return 0;
        int foundLeft = numberOfNodesFound(node.left);
        int foundRight = numberOfNodesFound(node.right);
        int totalFound = foundLeft + foundRight;
        if(nodeSet.contains(node)){
            totalFound++;
        }
        if(lca == null && totalFound == nodeSet.size()){
            lca = node;
        }
        return totalFound;
    }
}

Last updated

Was this helpful?