【两次过】Lintcode 88. 最近公共祖先

给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。

最近公共祖先是两个节点的公共的祖先节点且具有最大深度。

样例

对于下面这棵二叉树

  4
 / \
3   7
   / \
  5   6

LCA(3, 5) = 4

LCA(5, 6) = 7

LCA(6, 7) = 7

注意事项

假设给出的两个节点都在树中存在


解题思路:

我们可以用深度优先搜索,从叶子节点向上,标记子树中出现目标节点的情况。如果子树中有目标节点,标记为那个目标节点,如果没有,标记为null。显然,如果左子树、右子树都有标记,说明就已经找到最小公共祖先了。如果在根节点为p的左右子树中找p、q的公共祖先,则必定是p本身。

换个角度,可以这么想:如果一个节点左子树有两个目标节点中的一个,右子树没有,那这个节点肯定不是最小公共祖先。如果一个节点右子树有两个目标节点中的一个,左子树没有,那这个节点肯定也不是最小公共祖先。只有一个节点正好左子树有,右子树也有的时候,才是最小公共祖先。

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */


public class Solution {
    /*
     * @param root: The root of the binary search tree.
     * @param A: A TreeNode in a Binary.
     * @param B: A TreeNode in a Binary.
     * @return: Return the least common ancestor(LCA) of the two nodes.
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
        // write your code here
        //发现目标节点则通过返回值标记该子树发现了某个目标结点
        if(root == null || root == A || root == B) return root;
        
        //Divide
        //查看左子树中是否有目标结点,没有为null
        TreeNode left = lowestCommonAncestor(root.left, A, B);
        //查看右子树是否有目标节点,没有为null
        TreeNode right = lowestCommonAncestor(root.right, A, B);
        
        //Conquer
        //都不为空,说明左右子树都有目标结点,则公共祖先就是本身
        if(left!=null && right!=null) return root;
        //如果发现了目标节点,则继续向上标记为该目标节点
        return left == null ? right : left;
    }
}

复杂版:

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */


public class Solution {
    /*
     * @param root: The root of the binary search tree.
     * @param A: A TreeNode in a Binary.
     * @param B: A TreeNode in a Binary.
     * @return: Return the least common ancestor(LCA) of the two nodes.
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
        //若节点A与B分别在root的两边,则root本身为最近公共祖先
        boolean both = (isIn(root.left, A) && isIn(root.right, B)) || (isIn(root.right, A) && isIn(root.left, B));
        if(both)
            return root;
        
        //若节点A与B都在root的左侧,则继续去左边查找最近公共祖先
        boolean left = isIn(root.left, A) && isIn(root.left, B);
        if(left)
            return lowestCommonAncestor(root.left, A, B);
        
        //若节点A与B都在root的右侧,则继续去右边查找最近公共祖先
        boolean right = isIn(root.right, A) && isIn(root.right, B);
        if(right)
            return lowestCommonAncestor(root.right, A, B);
        
        //其他情况返回root,例如root==null,或者root==A,或者root==B
        return root;
    }
    
    //在以root为根的二叉树中查找是否存在node节点
    private boolean isIn(TreeNode root, TreeNode node){
        if(root == null)
            return false;
        
        if(root.val == node.val)
            return true;
        
        return isIn(root.left, node) || isIn(root.right, node);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值