I've found a solution to this problem, in this code,
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return null;
if(root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
return left != null && right != null ? root : left == null ? right : left;
}
I just can't seem to understand the last line. Can someone help me understand how the code works in the last line.
I assume you're aware this makes use of the ternary operator.
It might be easier to understand if you saw it surrounded with parenthesis:
return (left != null && right != null ? root : (left == null ? right : left));
Meaning, this could be rewritten as the following nested if:
if (left != null && right != null) {
return root;
} else {
if (left == null) {
return right;
} else {
return left;
}
}
So let's break it down. You've already checked recursively the left child sub-tree and the right child sub-tree. Now you need to decide which node you're going to return.
If both children exist (left != null && right != null), then the lowest common ancestor of both sub-trees is the current node, meaning the root, which is why you return it.
If however, one of the sub-trees doesn't exist, for instance in the following case when looking at node2 who only has one child:
root
/ \
node1 node2
/ \ \
node3 node4 node5
Then the root cannot be the lowest common ancestor, which means it has to be in one of the sub-trees. Since one of them is null (doesn't exist), then it has to be in the other.
So if left == null then return the lowest common ancestor you've found on the right sub-tree, otherwise the right-subtree doesn't exist (is null) and so return the lowest common ancestor you've found on the left sub-tree.
The ternary operator is used to determine which value is returned. It mighy be a bit clearer if you set braces appropriatly:
return (left != null && right != null) ? root : ((left == null) ? right : left);
Alternatively, you can rewrite the statement to use if's, which might make it a bit clearer:
if (left != null && right != null) {
return root;
} else {
if (left == null) {
return right;
} else {
return left;
}
}
Related
I'm looking at two solutions to find the first common ancestor of two nodes in a binary tree (not necessarily a binary search tree). I've been told the second solution provides a better worst-case run time, but I can't figure out why. Can someone please enlighten me?
Solution 1:
Find the depth of each of the two nodes: p,q
Calculate the delta of their depths
Set a pointer at the shallower node a pointer a the deeper node
Move the deeper node pointer up by the delta so we can start traversing from the same height
Recursively visit the part nodes of both pointers until we arrive at the same node which is out the first common ancestor
import com.foo.graphstrees.BinaryTreeNodeWithParent;
/*
Find the first common ancestor to 2 nodes in a binary tree.
*/
public class FirstCommonAncestorFinder {
public BinaryTreeNodeWithParent find(BinaryTreeNodeWithParent p, BinaryTreeNodeWithParent q) {
int delta = depth(p) - depth(q);
BinaryTreeNodeWithParent first = delta > 0 ? q: p; // use shallower node
BinaryTreeNodeWithParent second = delta > 0 ? p: q; //use deeper
second = goUp(second, delta); // move up so they are level, if 1 node is deeper in the tree than the other, their common ancestor obviously cannot be below the shallower node, so we start them off at the same height in the tree
//keep going up the tree, once first == second, stop
while(!first.equals(second) && first !=null && second !=null) {
first = first.getParent();
second = second.getParent();
}
return first == null || second == null ? null : first;
}
private int depth(BinaryTreeNodeWithParent n) {
int depth = 0;
while (n != null) {
n = n.getParent();
depth++;
}
return depth;
}
private BinaryTreeNodeWithParent goUp(BinaryTreeNodeWithParent node, int delta) {
while (delta > 0 && node != null) {
node = node.getParent();
delta--;
}
return node;
}
}
Solution 2:
Verify both nodes (p,q) exist in the tree starting at the root node
Verify that q is not a child of p and p is not a child of q by traversing their subtrees
Recursively examine subtrees of successive parent nodes of p until q is found
import com.foo.graphstrees.BinaryTreeNodeWithParent;
public class FirstCommonAncestorImproved {
public BinaryTreeNodeWithParent find(BinaryTreeNodeWithParent root,
BinaryTreeNodeWithParent a,
BinaryTreeNodeWithParent b) {
if (!covers(root, a) || !covers(root, b)) {
return null;
} else if (covers(a, b)) {
return a;
} else if (covers(b, a)) {
return b;
}
var sibling = getSibling(a);
var parent = a.getParent();
while (!covers(sibling, b)) {
sibling = getSibling(parent);
parent = parent.getParent();
}
return parent;
}
private BinaryTreeNodeWithParent getSibling(BinaryTreeNodeWithParent node) {
if (node == null || node.getParent() == null) return null;
var parent = node.getParent();
return node.equals(parent.getLeft()) ? node.getRight() : node.getLeft();
}
private boolean covers(BinaryTreeNodeWithParent root,
BinaryTreeNodeWithParent node) {
if (root == null) return false;
if (root.equals(node)) return true;
return covers(root.getLeft(), node) || covers(root.getRight(), node);
}
}
It depends on the structure of the problem.
If the starting nodes are deep in a big tree, and the ancestor is close by, then the first algorithm will still need to traverse the entire path to the root to find the depths. The second will succeed by inspecting only a small subtree.
On the other hand, if the nodes are deep and the common ancestor is very near the root, then the first will only traverse two paths to the root, while the second may explore the entire tree.
Note that as is often the case you can get an asymptotically faster algorithm by trading space for speed. Maintain a set of nodes. Traverse upward in alternating steps from both starting nodes, adding to the set until you find one that's already there. That's the common ancestor. Given the set operations are O(1), this algorithm is O(k) where k is the path length from the common ancestor to the most distant start node. You can't do better.
Set<Node> visited = new HashSet<>();
while (a != null && b != null) {
if (visited.contains(a)) return a;
if (visited.contains(b)) return b;
visited.add(a);
visited.add(b);
a = a.parent();
b = b.parent();
}
while (a != null) {
if (visited.contains(a)) return a;
a = a.parent();
}
while (b != null) {
if (visited.contains(b)) return b;
b = b.parent();
}
return null;
I'm coding a program and i need to know if a BST is symmetric in its structure
public void traverse (Layer root){
if (root.leftChild != null){
traverse (root.leftChild);
}
if (root.rightChild != null){
traverse (root.rightChild);
}
I have the traverse code but i dont know how to check if it is symmetric
Thanks for the help
I learned how to do this during school, and this is what I did. I learned it from a website I can't remember, but I kept the comments in it.
boolean isMirror(Node node1, Node node2)
{
// if both trees are empty, then they are mirror image
if (node1 == null && node2 == null)
return true;
// For two trees to be mirror images, the following three
// conditions must be true
// 1 - Their root node's key must be same
// 2 - left subtree of left tree and right subtree
// of right tree have to be mirror images
// 3 - right subtree of left tree and left subtree
// of right tree have to be mirror images
if (node1 != null && node2 != null && node1.key == node2.key)
return (isMirror(node1.left, node2.right)
&& isMirror(node1.right, node2.left));
// if neither of the above conditions is true then
// root1 and root2 are mirror images
return false;
}
boolean isSymmetric(Node node)
{
// check if tree is mirror of itself
return isMirror(node, node);
}
public boolean isSymmetric(Layer root) {
return root == null || isSymmetric(root.left, root.right);
}
public boolean isSymmetric(Layer left, Layer right) {
if (left == null && right == null) return true;
return left != null && right != null && left.val == right.val && isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left);
}
I suppose that you mean that tree is symmetric if it is form a "mirror" of itself
I have a serious problem with recurive search of subtree in onether one.
I try this but...
public static boolean containsTree (Node t1, Node t2)
{
if (t2 == null)
return true;
// Empty tree is always a subtree.
else
return subTree(t1, t2);
}
public static boolean subTree (Node t1, Node t2)
{
if (t1 == null)
return false; // Big tree is over.
if (t1.getName().equalsIgnoreCase(t2.getName()))
return matchTree(t1, t2);
return (subTree(t1.getChild(), t2) || subTree(t1.getBrother(), t2));
}
private static boolean matchTree (Node t1, Node t2)
{
if (t1 == null && t2 == null)
return true; // Both trees are empty.
if (t1 == null || t2 == null)
return false; // Big tree empty and subtree still not found.
if (!t1.getName().equalsIgnoreCase(t2.getName()))
return false;
return (matchTree(t1.getChild(), t2.getChild()) && matchTree(
t1.getBrother(), t2.getBrother()));
}
seems to be not correctly formed.
the containsTree function, stop to search when find a node that is different from onether one.
Below, you can find an example of two tree.
1
/ \ 3
/ \ /\
/ \ / \
2 3 7 8
/\ /\
/ \ / \
3 4 5 6
\
3
/\
/ \
7 8
In this case when the function compare the subtree on the right with subtree on the left, it stop to search when find equals parent node but it have different child node.
I need that the function don't stop to search but go throw this point and search for all other child node and their subtree.
say our class is like this:
class Node{
node left, right;
int value;
boolean equals(Node n){
// if one child is null we can skip
if(this.left == null && this.left != null ||
this.left != null && this.left == null ){
return false;
}
if(this.right == null && this.right != null ||
this.right != null && this.right == null ){
return false;
}
//
return (this.value == n.value) &&
( this.left == null || (this.left.equals(n.left)) ) &&
// if this.left == null, n.left is null too and the || will skip the equals()
( this.right == null || (this.right.equals(n.right)) );
// same for right
}
}
this method will recursively check if a tree looks the same as another
so, lets check if its a subtree:
boolean isSubTree(Node other){
return this.equals(other) ||
(other.left != null && this.isSubTree(other.left)) ||
// if left is null, this cant be a subtree
(other.right != null && this.isSubTree(other.right));
// same for right
}
Nothing tested but i think it could be work like this. I skipped constructors and other functions.
(bit overloaded return statements :P )
you should keep some things in your mind: trees are usually used to search for values, and are mostly implemented as binary trees were: left-child < parent < right-child
edit
obviously you should make sure that your tree does not circle :P
I have written a code for finding least common ancestor of nodes in binary tree but it seems to return null instead of the LCA.
My algorithm is as below.
Recursively find the ancestor in left and right branch of tree
A node where left as well as right tree has matching elements in the LCA.
public class LCA {
public static BinaryTreeNode findLCA( BinaryTreeNode root, BinaryTreeNode node1 , BinaryTreeNode node2) {
if (root == null) {
return null;
}
BinaryTreeNode left = root.getLeft();
BinaryTreeNode right = root.getRight();
if (left != null && (left == node1 || left == node2)) {
return root;
}
if (right != null && (right == node1 || right == node2)) {
return root;
}
if (( findLCA(left, node1, node2) != null) && (findLCA(right, node1, node2) != null)) {
return root;
}
return null; }}
What could be the problem with this code?
I think I am able to fix it. I added another condition to see if my recursive findLCA is returning something. If so I return the same value further which fixed the issue. Plz provide your comments if this design is ok.
public static BinaryTreeNode findLCA( BinaryTreeNode root, BinaryTreeNode node1 , BinaryTreeNode node2) {
if (root == null) {
return null;
}
BinaryTreeNode left = root.getLeft();
BinaryTreeNode right = root.getRight();
BinaryTreeNode lcaNode1;
BinaryTreeNode lcaNode2;
if (left != null && (left == node1 || left == node2)) {
return root;
}
if (right != null && (right == node1 || right == node2)) {
return root;
}
lcaNode1 = findLCA(left, node1, node2);
lcaNode2 = findLCA(right, node1, node2);
if (( lcaNode1 != null) && lcaNode2 != null) {
return root;
}
if (lcaNode1 != null) {
return lcaNode1;
}
if (lcaNode2 != null) {
return lcaNode2;
}
return null;
}
I have written the below code for recursively searching binary tree .
Even though my system.out statement is getting executed , the return statement is not returning out of entire recursion and thus this method not returning true.
Can anyone suggest how can I return out of entire recursion.?
public static boolean isElementinTree(int num, BinaryTreeNode root)
{
if (root != null)
{
int rootVal = root.getData();
BinaryTreeNode left = root.getLeft();
BinaryTreeNode right = root.getRight();
if (left != null)
{
isElementinTree(num,left);
}
if (right != null)
{
isElementinTree(num,right);
}
if (num == rootVal)
{
System.out.println("------ MATCH -----");
return true;
}
}
return false;
}
This is the problem:
if (left != null)
{
isElementinTree(num,left);
}
if (right != null)
{
isElementinTree(num,right);
}
You're calling the method in those cases - but ignoring the result. I suspect you just want to change each of those to return immediately if it's found:
if (left != null && isElementinTree(num, left))
{
return true;
}
if (right != null && isElementinTree(num, right))
{
return true;
}
Or to make the whole thing more declarative, you can do it more simply:
public static boolean isElementinTree(int num, BinaryTreeNode root)
{
return root != null && (root.getData() == num ||
isElementInTree(num, root.getLeft()) ||
isElementInTree(num, root.getRight()));
}
It's fine to call isElementInTree with a null second argument, as you're already protecting against that with the first part.
What is wrong with a simple solution like this:
public static boolean isElementinTree(int num, BinaryTreeNode root)
{
return root != null && //The tree is non-null
(num == root.getData() || //We have num in this node OR
isElementInTree(num, root.getLeft()) || //We have num in left subtree OR
isElementInTree(num, root.getRight()) ); //We have num in right subtree
}
You need to check if the value is in one of the branches, and save that result.
Initialize a variable boolean found = false;.
When you do the recursive call, you need to do something like:
found = isElementinTree(num,left)
same thing for the right side.
At the end, instead of returning false, check if the value was found on a branch, simply return found;
Also, first check if the number you are looking for isn't on the Node itself, instead of searching each branch first. Simply switch the order of the if's.
If you do find the element you're looking for in the left or right subtrees you need to return this fact back up to the caller:
if (left != null)
{
if(isElementinTree(num,left)) return true;
}
if (right != null)
{
if(isElementinTree(num,right)) return true;
}
Only if you find it in none of the left tree, right tree and current node do you eventually fall through to the final return false.
Recursion solution:
boolean isElementinTree (int num, BinaryTreeNode root)
{
if(root == null)
return false;
if(root.value == num)
return true;
boolean n1 = isElementinTree(num,root.getLeft());
boolean n2 = isElementinTree(num,root.getRight());
return n1 ? n1 : n2;
}