This code finds a common ancestor. If one of the input does not exist in the tree then throws an exception. This does not use extra storage. It does not even traverse more than what it should be. It would also account for duplicate node values in binary tree.
I want you to pick my code apart and give me some feedback on how I could make it better or more simple.
public class LeastCommonAncestor {
private TreeNode root;
private static class TreeNode {
TreeNode left;
TreeNode right;
int item;
TreeNode (TreeNode left, TreeNode right, int item) {
this.left = left;
this.right = right;
this.item = item;
}
}
public void createBinaryTree (Integer[] arr) {
if (arr == null) {
throw new NullPointerException("The input array is null.");
}
root = new TreeNode(null, null, arr[0]);
final Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
final int half = arr.length / 2;
for (int i = 0; i < half; i++) {
if (arr[i] != null) {
final TreeNode current = queue.poll();
final int left = 2 * i + 1;
final int right = 2 * i + 2;
if (arr[left] != null) {
current.left = new TreeNode(null, null, arr[left]);
queue.add(current.left);
}
if (right < arr.length && arr[right] != null) {
current.right = new TreeNode(null, null, arr[right]);
queue.add(current.right);
}
}
}
}
private static class LCAData {
TreeNode lca;
int count;
public LCAData(TreeNode parent, int count) {
this.lca = parent;
this.count = count;
}
}
public int leastCommonAncestor(int n1, int n2) {
if (root == null) {
throw new NoSuchElementException("The tree is empty.");
}
LCAData lcaData = new LCAData(null, 0);
foundMatchAndDuplicate (root, lcaData, n1, n2, new HashSet<Integer>());
if (lcaData.lca != null) {
return lcaData.lca.item;
} else {
throw new IllegalArgumentException("The tree does not contain either one or more of input data. ");
}
}
private boolean foundMatchAndDuplicate (TreeNode node, LCAData lcaData, int n1, int n2, Set<Integer> set) {
if (node == null) {
return false;
}
// when both were found
if (lcaData.count == 2) {
return false;
}
// when only one of them is found
if ((node.item == n1 || node.item == n2) && lcaData.count == 1) {
if (!set.contains(node.item)) {
lcaData.count++;
return true;
}
}
boolean foundInCurrent = false;
// when nothing was found (count == 0), or a duplicate was found (count == 1)
if (node.item == n1 || node.item == n2) {
if (!set.contains(node.item)) {
set.add(node.item);
lcaData.count++;
}
foundInCurrent = true;
}
boolean foundInLeft = foundMatchAndDuplicate(node.left, lcaData, n1, n2, set);
boolean foundInRight = foundMatchAndDuplicate(node.right, lcaData, n1, n2, set);
if (((foundInLeft && foundInRight) ||
(foundInCurrent && foundInRight) ||
(foundInCurrent && foundInLeft)) &&
lcaData.lca == null) {
lcaData.lca = node;
return true;
}
return foundInCurrent || (foundInLeft || foundInRight);
}
}