二棵树某两个节点的公共祖先。Lowest Common Ancestor

Related leetcode questions:

BST:

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

BT, node always in the tree.

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/

BT, Node might not be in the tree

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-ii/

BT, with parent pointer.

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-iii/

 BT, multiple nodes(>2) to find LCA

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-iv/

 

1. 如果是有parent指针的树,可以转化成 求两个链表第一个公共节点的问题。

对于无parent指针普通二叉树(假定这两个节点一定在树中,否则需要先遍历一边树查找是否存在该节点

  1. (剑指offer的解法),先用一定的空间记录从根节点到两个节点各自的路径,然后找这两个路径最后一个相交的节点。

  2.  CC150,递归求解。 

普通二叉树解法, 时空复杂度O(N)

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/

/**
    假定已经得知p、q 两节点一定在树中i
*/

TreeNode commonAncestor(TreeNode root, TreeNode p, TreeNode q){
    
  //base condition
  if(root==null) return null; if(root==p||root==q) return root;
  //recursion TreeNode left
= commonAncestor(root.left,p,q); TreeNode right= commonAncestor(root.right,p,q); if(left!=null&&right!=null){ return root; } else if(left!=null){ return left; } else if(right!=null){ return right; } else return null; }

 

二叉搜索树

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

利用BST 的特性递归执行,时空O(N).

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        int rootVal = root.val;
        int pVal = p.val;
        int qVal = q.val;
        
        if(pVal > rootVal && qVal > rootVal){
            return lowestCommonAncestor(root.right,p,q);
        } else if(pVal < rootVal && qVal < rootVal){
            return lowestCommonAncestor(root.left,p,q);
        } else {
            return root;
        }
        
    }
}

Iterative的解法空间可以降到O(1).

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        int pVal = p.val;
        int qVal = q.val;
        
        while(root != null){
        
            if(pVal> root.val && qVal>root.val){
                root = root.right;
            } else if(pVal<root.val && qVal<root.val){
                root = root.left;
            } else {
                return root;
            }
        }
        return null;
        
    }
}

 

LCA,node可能不在树中的情况

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-ii/

思路1: 第一遍搜索两个结点是否在树中,第二遍遍历同上方法。

思路2;一遍遍历,需要返回node和node数量,根据不同的情况分析。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        Result res = lCAHelper(root,p,q);
        if(res.num<2){
            return null;
        }
        return res.node;
    }
    
    private Result lCAHelper(TreeNode root, TreeNode p, TreeNode q){
        if(root == null){
            return new Result(root,0);
        }
        
        //need to calculate the subtree first
        Result left = lCAHelper(root.left,p,q);
        Result right = lCAHelper(root.right,p,q);
        
        if(root == p || root == q){
            return new Result(root, 1+left.num+right.num);
        }
        
        if(left.node!=null&&right.node!=null){
            return new Result(root, 2);
        }
        
        return left.node!=null?left:right;
        
    }
    
    class Result{
        TreeNode node;
        int num;
        
        public Result(TreeNode node, int num){
            this.node = node;
            this.num = num;
        }
    }
}

 

 有父指针的情况下。

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-iii/

思路1: 相当于两个链表找相交节点。先算出各自长度及长度差,然后同步移动到相交。

思路2: 一条链表遍历到root然后接到另一条上,最终会在common node处相交。

class Solution {
    public Node lowestCommonAncestor(Node p, Node q) {
        int lenP = 0;
        int lenQ = 0;
        Node cur = p;
        while(cur!=null){
            lenP++;
            cur = cur.parent;
        }
        cur = q;
        while(cur!=null){
            lenQ++;
            cur = cur.parent;
        }
        int diff = lenP>lenQ?lenP-lenQ:lenQ-lenP;
        while(diff>0){
            if(lenP>lenQ){
                p = p.parent;
            }else{
                q = q.parent;
            }
            diff--;
        }
        
        while(p!=q){
            p = p.parent;
            q = q.parent;
        }
        
        return p;
    }
}

 

class Solution {
    public Node lowestCommonAncestor(Node p, Node q) {
        Node a = p;
        Node b = q;
        
        while(a!=b){
            a = (a == null?q:a.parent);
            b = (b == null?p:b.parent);
        }
        
        return a;
    }
}

 

多个节点的LCA

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-iv/

思路:跟2个节点几乎一样的解法。区别是判断root是否在set中。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode[] nodes) {
        Set<TreeNode> nodeSet = new HashSet<>();
        for(TreeNode each: nodes){
            nodeSet.add(each);
        }
        return lCA(root, nodeSet);
    }
    
    private TreeNode lCA(TreeNode root, Set<TreeNode> nodeSet){
        if(root == null){
            return null;
        }
        
        if(nodeSet.contains(root)){
            return root;
        }
        
        TreeNode left = lCA(root.left, nodeSet);
        TreeNode right = lCA(root.right, nodeSet);
        
        if(left!=null&&right!=null){
            return root;
        }
        
        return left!=null?left:right;
        
    }
}

 

参考:

https://www.youtube.com/watch?v=NP9n3ebk620

 

posted @ 2014-08-21 00:55  jdflyfly  阅读(213)  评论(0编辑  收藏  举报