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).”
_______3______
/ \
___5__ ___1__
/ \ / \
6 _2 0 8
/ \
7 4
For example, the lowest common ancestor (LCA) of nodes
Code (Java):
5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition./**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
private TreeNode[] level = new TreeNode[100000];
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == null || q == null) {
return null;
}
List<TreeNode> path1 = new ArrayList<TreeNode>();
List<TreeNode> path2 = new ArrayList<TreeNode>();
if (!verticalTraverse(root, p, path1, 0)) {
return null;
}
if (!verticalTraverse(root, q, path2, 0)) {
return null;
}
TreeNode result = null;
int i = 0;
int j = 0;
while (i < path1.size() && j < path2.size()) {
if (path1.get(i) != path2.get(j)) {
return path1.get(i - 1);
}
i++;
j++;
}
return path1.get(i - 1);
}
private boolean verticalTraverse(TreeNode root, TreeNode p, List<TreeNode> path, int i) {
if (root == null) {
return false;
}
level[i] = root;
if (root == p) {
for (int j = 0; j <= i; j++) {
path.add(level[j]);
}
return true;
}
if (root.left != null && verticalTraverse(root.left, p, path, i + 1)) {
return true;
}
if (root.right != null && verticalTraverse(root.right, p, path, i + 1)) {
return true;
}
return false;
}
}
A neat Divide-and-Conquer solution:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
// Divide
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
if (left != null) {
return left;
}
if (right != null) {
return right;
}
return null;
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == null || q == null) {
return null;
}
List<TreeNode> list1 = new ArrayList<>();
List<TreeNode> list2 = new ArrayList<>();
if (!getPath(root, p, list1)) {
return null;
}
if (!getPath(root, q, list2)) {
return null;
}
int i = 0;
for (i = 0; i < list1.size() && i < list2.size(); i++) {
if (list1.get(i) != list2.get(i)) {
return list1.get(i - 1);
}
}
return list1.get(i - 1);
}
private boolean getPath(TreeNode root, TreeNode target, List<TreeNode> result) {
if (root == null) {
return false;
}
result.add(root);
if (root == target) {
return true;
}
if (root.left != null) {
if (getPath(root.left, target, result)) {
return true;
} else {
result.remove(result.size() - 1);
}
}
if (root.right != null) {
if (getPath(root.right, target, result)) {
return true;
} else {
result.remove(result.size() - 1);
}
}
return false;
}
}
Follow-up:
What if there is a pointer to the parent?
Method 1: traditional method by using extra space
public class Solution {
private ArrayList<TreeNode> getPath2Root(TreeNode node) {
ArrayList<TreeNode> list = new ArrayList<TreeNode>();
while (node != null) {
list.add(node);
node = node.parent;
}
return list;
}
public TreeNode lowestCommonAncestor(TreeNode node1, TreeNode node2) {
ArrayList<TreeNode> list1 = getPath2Root(node1);
ArrayList<TreeNode> list2 = getPath2Root(node2);
int i, j;
for (i = list1.size() - 1, j = list2.size() - 1;
i >= 0 && j >= 0; i--, j--) {
if (list1.get(i) != list2.get(j)) {
return list1.get(i).parent;
}
}
return list1.get(i+1);
}
}
Method 2: without using extra space
public Node findLCA(Node root, Node p, Node q) {
if (root == null || p == null || q == null) return null;
int depth1 = getDepth(root, p);
int depth2 = getDepth(root, q);
if (depth1 > depth2) {
swap(depth1, depth2);
swap(p, q);
}
for (int i = 0; i < depth1 - depth2; i++) {
q = q.parent;
}
while (p) {
if (p == q) return p;
p = p.parent;
q = q.parent;
}
return null;
}
public int getDepth(Node root, Node n) {
if (root == null || n == null) return null;
int depth = 0;
while (root != n) {
depth++;
n = n.parent;
}
return depth;
}
public void swap(Object<T> a, Object<T> b) {
Object<T> tmp = a;
a = b;
b = tmp;
}
No comments:
Post a Comment