Definition of LCA
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).
Algorithm 1
- find path from root to n1
- find path from root to n2
- traverse both paths until the nodes are not same, return previous node
Find a path from root to given node
- DFS search like preorder traverse in recursive version
- base case if root is
null
returnfalse
- otherwise, if root is the given node return
true
- otherwise, put the node to the end of a
LinkedList
- traverse left-subtree and right-subtree
- if one of return value of two traversals is true, return true;
- otherwise, remove the last node in the
LinkedList
and return false;
Complexity
- Time complexity: Worse case
O(N)
(N
is number of nodes in the binary tree)- find path: Worse case
O(N)
- find previous node before first different nodes: Worse Case
O(H)
(H
is height of the binary tree)
- find path: Worse case
- Space complexity:
O(H)
(H
is height of the binary tree)- we need a
LinkedList
to store the path, and the length of path isH
- we need a
Code
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
LinkedList<TreeNode> pathToP = new LinkedList<TreeNode>();
LinkedList<TreeNode> pathToQ = new LinkedList<TreeNode>();
if (!getPath(root, pathToP, p) || !getPath(root, pathToQ, q)) {
return null;
}
Iterator<TreeNode> traverseP = pathToP.iterator();
Iterator<TreeNode> traverseQ = pathToQ.iterator();
TreeNode pre = null;
while(traverseP.hasNext() && traverseQ.hasNext()) {
TreeNode curP = traverseP.next();
TreeNode curQ = traverseQ.next();
if (curP == curQ) {
pre = curP;
} else {
break;
}
}
return pre;
}
private boolean getPath(TreeNode root, LinkedList<TreeNode> path, TreeNode target) {
if (root == null) {
return false;
}
path.add(root);
if (root == target) {
return true;
}
if (getPath(root.left, path, target) || getPath(root.right, path, target)) {
return true;
}
path.removeLast();
return false;
}
Algorithm 2
- traverse the tree start from root
- if any target nodes matches the root, return root
- else we traverse the left subtree and right subtree
- if the root which has a target node in its left subtree and another in its right subtree, the root is LCA
- if the two target nodes at left subtree, the LCA has been found
- if the two target nodes at right subtree, the LCA has been found
Code
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return LCA(root, p, q);
}
private TreeNode LCA(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
if (root == p || root == q) {
return root;
}
TreeNode left = LCA(root.left, p, q);
TreeNode right = LCA(root.right, p, q);
if (left != null && right != null) {
return root;
}
return (left == null)? right: left;
}
网友评论