问题描述
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 v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).” 地址
问题分析
求给定一棵二叉树的头节点, 以及这棵树中的两个节点p和q, 请返回这两个节点的最近的公共祖先节点。和 LeetCode 235. Lowest Common Ancestor of a Binary Search Tree 很像。只不过该题是求一颗普通二叉树的最近公共祖先 首先明确:
若这是一颗二叉搜索树 ,,若都小于root,那么递归左子树,若都大于root,递归右子树。否则,最近公共祖先为根节点 若这棵树有指向父节点的指针,那么就变成了两个单向链表的相交问题,找到第一个相交节点即可。 剑指offer-两个链表中第一个公共结点 方法1:DFS(先序遍历)
首先是根:对于一棵树,如果根节点便是 p或者q中的一个 ,那么根节点 便是公共祖先节点,返回即可 如果递归左子树和右子树的结果都非空 ,那么说明,一个在左子树,一个在右子树,因为递归函数只有遇到p或者q才返回非空节点,所以最近公共祖先依旧是根节点 如果递归左子树和右子树的结果,一个为空,一个不为空 ,那么非空递归结果 即为最近公共祖先 时间复杂度: O(N) 方法2:
类似于先为每一个节点设置一个指向父节点的指针,然后找两条单链表相交的第一个交点。 用一个map存储节点以及该节点父节点信息 ,然后根据这个map可以得到从当前节点到根节点路径, 用一个set 存储从o1到根节点的路径,然后再从o2走向根节点 ,看路径中有没有经历已经存在set中的节点。建立map的过程为O(N),查询操作为O(logN) 方法2适用于多次查询 的情况,一旦建立了map,便可多次进行查询。关于这个问题,还有其他离线算法 的解法。
代码实现
public TreeNode lowestCommonAncestor (TreeNode root, TreeNode p, TreeNode q) {
if (root == null ) {
return null ;
}
if (p == root || q == root) {
return root;
}
TreeNode leftAncestor = lowestCommonAncestor(root.left, p, q);
TreeNode rightAncestor = lowestCommonAncestor(root.right, p, q);
if (leftAncestor != null && rightAncestor != null ) {
return root;
}
return leftAncestor == null ? rightAncestor : leftAncestor;
}
public TreeNode lowestCommonAncestor (TreeNode root, TreeNode p, TreeNode q) {
Record record = new Record(root);
return record.query(p, q);
}
class Record {
private HashMap<TreeNode, TreeNode> map;
public Record (TreeNode root) {
map = new HashMap<>();
if (root != null ) {
map.put(root, null );
}
setMap(root);
}
private void setMap (TreeNode root) {
if (root == null ) {
return ;
}
if (root.left != null ) {
map.put(root.left, root);
}
if (root.right != null ) {
map.put(root.right, root);
}
setMap(root.left);
setMap(root.right);
}
public TreeNode query (TreeNode p, TreeNode q) {
HashSet<TreeNode> p2Root = new HashSet<>();
TreeNode curNode = p;
while (curNode != null ) {
p2Root.add(curNode);
curNode = map.get (curNode);
}
curNode = q;
while (! p2Root.contains(curNode)) {
curNode = map.get (curNode);
}
return curNode;
}