二棵树某两个节点的公共祖先。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