Many answers on the net for 'finding Least Common Ancestor in binary tree' and its supplementary question 'find distance between 2 nodes' have 4 issues:
Does not consider duplicates
Does not consider if input node is invalid/absent/not in tree
Use extra / aux storage
Not truncating the traversal although answer is obtained.
I coded this sample to overcome all handicaps. but since I did not find 'a single' answer in this direction, I would appreciate if my code has a significant disadvantage which I am missing. Maybe there is none. Additional eyeballs appreciated.
public int distance(int n1, int n2) {
LCAData lcaData = new LCAData(null, 0, 0);
int distance = foundDistance (root, lcaData, n1, n2, new HashSet<Integer>());
if (lcaData.lca != null) {
return distance;
} else {
throw new IllegalArgumentException("The tree does not contain either one or more of input data. ");
}
}
private static class LCAData {
TreeNode lca;
int count;
public LCAData(TreeNode parent, int count) {
this.lca = parent;
this.count = count;
}
}
private int foundDistance (TreeNode node, LCAData lcaData, int n1, int n2, Set<Integer> set) {
assert set != null;
if (node == null) {
return 0;
}
// when both were found
if (lcaData.count == 2) {
return 0;
}
// when only one of them is found
if ((node.item == n1 || node.item == n2) && lcaData.count == 1) {
// second element to be found is not a duplicate node of the tree.
if (!set.contains(node.item)) {
lcaData.count++;
return 1;
}
}
int foundInCurrent = 0;
// when nothing was found (count == 0), or a duplicate tree node was found (count == 1)
if (node.item == n1 || node.item == n2) {
if (!set.contains(node.item)) {
set.add(node.item);
lcaData.count++;
}
// replace the old found node with new found node, in case of duplicate. this makes distance the shortest.
foundInCurrent = 1;
}
int foundInLeft = foundDistance(node.left, lcaData, n1, n2, set);
int foundInRight = foundDistance(node.right, lcaData, n1, n2, set);
// second node was child of current, or both nodes were children of current
if (((foundInLeft > 0 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInLeft > 0)) &&
lcaData.lca == null) {
// least common ancestor has been obtained
lcaData.lca = node;
return foundInLeft + foundInRight;
}
// first node to match is the current node. none of its children are part of second node.
if (foundInCurrent == 1) {
return foundInCurrent;
}
// ancestor has been obtained, aka distance has been found. simply return the distance obtained
if (lcaData.lca != null) {
return foundInLeft + foundInRight;
}
// one of the children of current node was a possible match.
return (foundInLeft + foundInRight) > 0 ? (foundInLeft + foundInRight) + 1 : (foundInLeft + foundInRight);
}
The algorithm appears to be (without pulling it apart entirely) to exhaustively traverse the entire tree until a node is found where there is one node found on the left and one on the right. And creating an additional set as you go.
The problem here seems to be that your algorithm is very inefficient. That may fit your requirements, if this particular operation is almost never carried out. But normally you could do better.
Related
In my program, I have initialized a binary tree and I want to search if a node exists in that binary tree. If it does exist, then I will print the subtree of that node and the level it was found. I am able to perform my search method but I am not sure how to print the subtree of that node found and its level.
For example, this is my binary tree [K=3 L=[K=1 R=[K=2]] R=[K=5 L=[K=4]]. If I search for node 1, then it will return the node (not null) since it exists in my binary tree.
Problem: I need to print only the subtree of the node and the level where it was found: [K=1 R=[K=2]], level=1.
Here is my source code for reference:
Main Class
// instantiate BST object
BST<Character> bst = new BST<>();
// insert values to bst1
String str = "31254";
char[] letter = str.toCharArray();
for (int i = 0; i < letter.length; i++) {
Character c = letter[i];
bst1.insert(c);
}
// print bst
System.out.println("\nht=" + bst1.height + " " + bst1.toString() + "\n");
// search values in bst1
String str2 = "016483";
char[] letter2 = str2.toCharArray();
for (int i = 0; i < letter2.length; i++) {
Character c = letter2[i];
if (bst1.search(c) != null) { // if found, print the node (w/ subtree) and its level
// ** part that should print the subtree and its level
}
else {
System.out.println(c + " is not found.");
}
}
BST Class - where my search method is declared
public class BST<T extends Comparable<T>> extends BT<T> {
// insert() method
// search method
public BTNode<T> search(T k) {// my method
BTNode<T> n = root;
while (n != null) {
if (n.info.compareTo(k) == 0) {
return n;
}
else {
if (n.info.compareTo(k) > 0) {
n = n.left;
}
else {
n = n.right;
}
}
}
return null;
}
}
Thanks in advance!
I did not modify your code. Instead, I used an imaginary class Node that I've written. Also, I have written all of them as half pseudo half java code.
Suppose your node has only one int type variable and two children.
class Node{
int data;
Node left;
Node right;
}
You have a printExistingSubTree method in your BST class that does the what you exactly ask for:
printExistingSubTree(Node node, int key):
if (find(node.left, key, 0) != -1)
then
printTree(node.left)
print(find(node.left, key, 0))
if (find(node.right, key, 0) != -1)
then printTree(node.right)
printTree(node.right)
print(find(node.right, key, 0))
You have a find method in your BST class that does find the index:
int find(Node node,int key, int level)
if(node.data is equal to the key)
then return level
int left = -1;
if(node.leftChild is not null)
then left = find(node.left, key, level+1)
if(left != -1)
return left
int right = -1;
if(node.rightChild is not null)
then right = find(node.right, key, level+1)
return right
Then, to print, you should decide how you want to traverse the subtree.
You have a printTree method in your BST class that prints the subtree in postorder:
void printTree(Node node){
if (node == null)
return;
printTree(node.left);
printTree(node.right);
print(node.data + " ");
}
Note: I did not understand your whole code. Therefore, I have just written the answer of your question in the pseudo code format. I think, you can write your own code from that.
Note2: There may be some typos&wrong namings. PLease do not lynch. Just write in the comments and I'll correct.
I am having trouble finding out if the number of nodes at each level is the same. The question and my code so far is provided below
Two binary trees are called similar sized if the number of nodes is the same at each level of the tree
Given the following:
class TreeNode {
String nodeValue;
TreeNode rightNode;
TreeNode leftNode;
TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
this.nodeValue = nodeValue;
this.rightNode = rightNode;
this.leftNode = leftNode;
}
}
The goal of this question is to write a function that will validate if two trees are similar sized.
The function should return true if this is correct and false otherwise
my code:
//implemented with java
class TreeNode {
String nodeValue;
TreeNode rightNode;
TreeNode leftNode;
TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
this.nodeValue = nodeValue;
this.rightNode = rightNode;
this.leftNode = leftNode;
}
//function to return size of node, i.e. number of children
int nodeSize() {
//if node has both left and right child node
if (this.rightNode.nodeValue != null && this.leftNode.nodeValue != null) {
return 2;
//if node has no child nodes
} else if (this.rightNode.nodeValue == null && this.leftNode.nodeValue == null) {
return 0;
//if node just has either left or right child node
} else {
return 1;
}
}
boolean similarSizedTrees(TreeNode firstTree, TreeNode secondTree) {
//if both nodes have no child nodes
if (firstTree.nodeSize() == 0 && secondTree.nodeSize() == 0) {
return true;
}
//if both nodes have at least 1 child node
if (firstTree.nodeSize() != 0 && secondTree.nodeSize() != 0) {
return ((firstTree.nodeSize() == secondTree.nodeSize()) &&
similarSizedTrees(firstTree.leftNode, secondTree.leftNode) &&
similarSizedTrees(firstTree.leftNode, secondTree.rightNode));
}
//
return false;
}
}
What I am having trouble with is my code does not account for the number of nodes at each level.
Your recursion based approach wouldn't work, because the number of nodes in the next level aren't influenced by which node each child descends from. You could modify your approach to use a simple level order traversal.
(Edit: adding #Piotr's explanation)
The basic idea is to count nodes on each level. In the example picture there is 1 node on level 1, 2 nodes on level 2 and 3 nodes on level 3 and finally 1 node on level 4. These numbers are exactly the same for both tree, even if they are not exactly the same. This algorithm is computing these counts for each level, and if discrepancy is found, it returns False. Otherwise it returns True in the end if both trees are similar. (I'm not well versed in Java, but you can easily translate the algorithm):
def similar(firstTree, secondTree):
queue1, queue2 = queue(firstTree), queue(secondTree) # create queues for traversal
# each queue stores all nodes in a given level
while queue1 and queue2:
if len(queue1)!=len(queue2): # check base condition
return False
i = 0
while i<len(queue1): # append all next level nodes for tree 1
node = queue1.pop()
if node.left:
queue1.insert(node.left)
if node.right:
queue1.insert(node.right)
i += 1
i = 0
while i<len(queue2): # append all next level nodes for tree 2
node = queue2.pop()
if node.left:
queue2.insert(node.left)
if node.right:
queue2.insert(node.right)
i += 1
if queue1 or queue2:
return False # either tree couldn't complete traversal because of different heights
return True
A couple solutions can be found here: https://www.techiedelight.com/check-if-two-binary-trees-are-identical-not-iterative-recursive/
this is the recursive function shown from the link mentioned above tailored to your code.
boolean similarSizedTrees(TreeNode x, TreeNode y) {
// bottom of tree reached
if (x == null && y == null) {
return true;
}
// both trees are non-empty and the value of their root node matches,
// recur for their left and right subtree
return (x != null && y != null) && (x.key == y.key) &&
similarSizedTrees(x.left, y.left) &&
similarSizedTrees(x.right, y.right);
}
EDIT: You could also keep count of the nodes at each level using two global int variables, one for each tree, as you traverse the tree increment each variable, then compare them together before continuing down to the next level.
Here is a solution using recursion:
int find_height(TreeNode t){
return (t == null)? 0 : 1 + Math.max(find_height(t.leftNode), find_height(t.rightNode));
}
boolean is_similar_tree(TreeNode l, TreeNode r){
int l_height = find_height(l);
int r_height = find_height(r);
if(l_height != r_height)
return false;
int[] l_height_sums = new int[l_height];
int[] r_height_sums = new int[r_height];
is_similar_tree_helper(l, l_height_sums, l_height);
is_similar_tree_helper(r, r_height_sums, r_height);
return Arrays.equals(l_height_sums, r_height_sums);
}
void is_similar_tree_helper(TreeNode t, int[] table, int height){
if(t == null || height == 0)
return;
table[height - 1]++;
is_similar_tree_helper(t.leftNode, table, height - 1);
is_similar_tree_helper(t.rightNode, table, height - 1);
}
The idea is to count the number of nodes in each level, then check if the total number of levels of two trees are the same or not. If it is not the same then return false otherwise check each level count and compare the value. If two values are equal then return true otherwise false.
class TreeNode {
String nodeValue;
TreeNode rightNode;
TreeNode leftNode;
TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
this.nodeValue = nodeValue;
this.rightNode = rightNode;
this.leftNode = leftNode;
}
public void countLevelNode(TreeNode root, int level, int[] sum) {
if(root == null) return;
sum[level]++;
countLevelNode(root.leftNode, level + 1, sum);
countLevelNode(root.rightNode, level + 1, sum);
}
boolean similarSizedTrees(TreeNode firstTree, TreeNode secondTree) {
int[] countFirstTreeNode = new int[1000];
int[] countSecondTreeNode = new int[1000];
int totalLevelofFirstTree = 0;
int totalLevelofSecondTree = 0;
countLevelNode(firstTree, totalLevelofFirstTree, countFirstTreeNode);
countLevelNode(secondTree, totalLevelofSecondTree, countSecondTreeNode);
if(totalLevelofFirstTree != totalLevelofSecondTree){
return false;
}
else{
for(int i = 0; i < totalLevelofFirstTree; i++){
if(countFirstTreeNode[i] != countSecondTreeNode[i]){
return false;
}
}
return true;
}
}
}
I am trying to implement a priority queue, using a triply linked data structure. I want to understand how to implement sink and swim operations, because when you use an array, you can just compute the index of that array and that's it. Which doesn't make sense when you use a triply-linked DS.
Also I want to understand how to correctly insert something in the right place, because when you use an array, you can just insert in the end and do a swim operation, which puts everything in the right place, how exactly do I compute that "end" in a linked DS?
Another problem would be removing the element with the biggest priority. To do that, for an array implementation, we just swap the last element with the first (the root) one and then, after removing the last element, we sink down the first one.
(This is a task from Sedgewick).
I posted this in case someone gets stuck doing this exercise from Sedgewick, because he doesn’t provide a solution for it.
I have written an implementation for maximum oriented priority queue, which can be modified according for any priority.
What I do is assign a size to each subtree of the binary tree, which can be defined recursively as size(x.left) + size(x.right) + 1. I do this do be able to find the last node inserted, to be able to insert and delete maximum in the right order.
How sink() works:
Same as in the implementation with an array. We just compare x.left with x.right and see which one is bigger and swap the data in x and max(x.left, x.right), moving down until we bump into a node, whose data is <= x.data or a node that doesn’t have any children.
How swim() works:
Here I just go up by doing x = x.parent, and swapping the data in x and x.parent, until x.parent == null, or x.data <= x.parent.
How max() works:
It just returns root.data.
How delMax() works:
I keep the last inserted node in a separate field, called lastInserted. So, I first swap root.data with lastInserted.data. Then I remove lastInserted by unhooking a reference to it, from its parent. Then I reset the lastInserted field to a node that was inserted before. Also we must not forget to decrease the size of every node on the path from root to the deleted node by 1. Then I sink the root data down.
How insert() works:
I make a new root, if the priority queue is empty. If it’s not empty, I check the sizes of x.left and x.right, if x.left is bigger in size than x.right, I recursively call insert for x.right, else I recursively call insert for x.left. When a null node is reached I return new Node(data, 1). After all the recursive calls are done, I increase the size of all the nodes on the path from root to the newly inserted node.
Here are the pictures for insert():
And here's my java code:
public class LinkedPQ<Key extends Comparable<Key>>{
private class Node{
int N;
Key data;
Node parent, left, right;
public Node(Key data, int N){
this.data = data; this.N = N;
}
}
// fields
private Node root;
private Node lastInserted;
//helper methods
private int size(Node x){
if(x == null) return 0;
return x.N;
}
private void swim(Node x){
if(x == null) return;
if(x.parent == null) return; // we're at root
int cmp = x.data.compareTo(x.parent.data);
if(cmp > 0){
swapNodeData(x, x.parent);
swim(x.parent);
}
}
private void sink(Node x){
if(x == null) return;
Node swapNode;
if(x.left == null && x.right == null){
return;
}
else if(x.left == null){
swapNode = x.right;
int cmp = x.data.compareTo(swapNode.data);
if(cmp < 0)
swapNodeData(swapNode, x);
} else if(x.right == null){
swapNode = x.left;
int cmp = x.data.compareTo(swapNode.data);
if(cmp < 0)
swapNodeData(swapNode, x);
} else{
int cmp = x.left.data.compareTo(x.right.data);
if(cmp >= 0){
swapNode = x.left;
} else{
swapNode = x.right;
}
int cmpParChild = x.data.compareTo(swapNode.data);
if(cmpParChild < 0) {
swapNodeData(swapNode, x);
sink(swapNode);
}
}
}
private void swapNodeData(Node x, Node y){
Key temp = x.data;
x.data = y.data;
y.data = temp;
}
private Node insert(Node x, Key data){
if(x == null){
lastInserted = new Node(data, 1);
return lastInserted;
}
// compare left and right sizes see where to go
int leftSize = size(x.left);
int rightSize = size(x.right);
if(leftSize <= rightSize){
// go to left
Node inserted = insert(x.left, data);
x.left = inserted;
inserted.parent = x;
} else{
// go to right
Node inserted = insert(x.right, data);
x.right = inserted;
inserted.parent = x;
}
x.N = size(x.left) + size(x.right) + 1;
return x;
}
private Node resetLastInserted(Node x){
if(x == null) return null;
if(x.left == null && x.right == null) return x;
if(size(x.right) < size(x.left))return resetLastInserted(x.left);
else return resetLastInserted(x.right);
}
// public methods
public void insert(Key data){
root = insert(root, data);
swim(lastInserted);
}
public Key max(){
if(root == null) return null;
return root.data;
}
public Key delMax(){
if(size() == 1){
Key ret = root.data;
root = null;
return ret;
}
swapNodeData(root, lastInserted);
Node lastInsParent = lastInserted.parent;
Key lastInsData = lastInserted.data;
if(lastInserted == lastInsParent.left){
lastInsParent.left = null;
} else{
lastInsParent.right = null;
}
Node traverser = lastInserted;
while(traverser != null){
traverser.N--;
traverser = traverser.parent;
}
lastInserted = resetLastInserted(root);
sink(root);
return lastInsData;
}
public int size(){
return size(root);
}
public boolean isEmpty(){
return size() == 0;
}
}
THIS IS HOMEWORK, DO NOT POST CODE. Please and thank you.
I have been assigned to create a method that calculates the depth of a particular in a BST.
To do this, I am to #Override a method public int depth(T data). So, to find it recursively, I need to create a helper method.
I know that I need to essentially search the tree for the node with the data I'm looking for. So, to do this, I've written the following code:
#Override
public int depth(T data) {
if (data == null) {
throw new IllegalArgumentException("Data is null");
}
if (compare(data, root.getData()) == 0) {
return 1;
} else {
return countNodes(search(root, data), data);
}
}
private int countNodes(BSTNode<T> node, T data) {
int depth = 1;
if (node == null) {
return 0;
} else {
if (compare(data, node.getData()) == 0) {
return depth;
} else if (compare(data, node.getData()) < 0) {
return countNodes(node.getLeft(), data);
} else {
return countNodes(node.getRight(), data);
}
}
}
private int compare(T a, T b) {
return a.compareTo(b);
}
However, this isn't going to work, as depth would remain 1 each time the recursive call is made; essentially, it's resetting the value of depth. I have no idea how to keep the value of depth in-between calls.
Your depth method should return one if the current node is the one you are looking for or the depth of the next node down plus one if you need to keep looking.
For example:
N5
N3 N7
N1 N4 N6
You want to know the depth of N1.
You start at the root:
N1 != N5 so you return one plus the result of your check on N3. (1 + (result of N3 check))
N1 != N3 so you return one plus the result of your check on N1. (1 + (1 + (result of N1 check)))
N1 == N1 so you you return one. (1 + (1 + (1)))
(1 + (1 + (1))) = 3
this is the correct depth and is what the initial depth call will return.
I'm trying to write a method for the maximum sum of a path through a binary tree:
public class ConsTree<T> extends BinaryTree<T>
{
BinaryTree<T> left;
BinaryTree<T> right;
T data;
public int maxSum()
{
}
}
As is shown, each tree contains a tree to its left and to its right, as well as a data of a generic type. I am somewhat confused on how to go about starting this. If someone could provide help as to what the algorithm might look like or put me in the right direction, that would be great. Thanks.
The way to think recursively is to consider the cases. In our case, we look at a single node and can decide what paths it has:
If the node has no children, then the only path is the singleton path (consisting of that node by itself).
If the node has only one child, then all paths go through that child.
Otherwise, the node has two children. Then, all paths go through one of its two children.
In case 1, the maximum must be that node's value. In case 2, the maximum is that node's value, plus the max-path-sum of its child (since that path is extended to a path for the parent through the only child). In case 3, the maximum is the maximum max-path-sum of its two children (since the best path must go through one of the two children, and the parent can see which of the children's best paths is better).
Therefore, the code is really simple. Here, since you return an int, I'm going to assume T = int.
public int maxSum() {
/* case 1 */
if(left == null && right == null)
return data;
/* case 2 */
if(right == null)
return data + left.maxSum();
else if(left == null)
return data + right.maxSum();
/* case 3 */
return Math.max(data + left.maxSum(), data + right.maxSum());
}
private static int max = Integer.MIN_VALUE;
public static int maxPathSum(TreeNode root) {
int rd = dfs(root);
return rd > max ? rd : max;
}
// close paths:
// 1 left leaf
// 2 right leaf
// 3 left + root + right
//
// open paths:
// 4 root
// 5 left + root
// 6 right + root
private static int dfs(TreeNode root) {
if (root.left == null && root.right == null) {
return root.val;
}
if (root.left == null && root.right != null) {
int rPathMax = dfs(root.right);
max = rPathMax > max ? rPathMax : max;
return Math.max(root.val, rPathMax + root.val);
}
if (root.right == null && root.left != null) {
int lPathMax = dfs(root.left);
max = lPathMax > max ? lPathMax : max;
return Math.max(root.val, lPathMax + root.val);
}
int lPathMax = dfs(root.left);
int rPathMax = dfs(root.right);
int closePathMax = lPathMax + rPathMax + root.val;
int innerMax = Math.max(closePathMax, Math.max(lPathMax, rPathMax));
max = innerMax > max ? innerMax : max;
return Math.max(root.val, Math.max(lPathMax + root.val, rPathMax + root.val));
}