The method is supposed to take in two parameters one for depth and one for the integer value of the root of the tree. For Example: for any given N, returns the root reference of a full binary search tree of depth N such that the nodes store the integers 1, 2, …, 2 N+1 – 1. I'm struggling to get this right. Here is what I have:
public static BinaryNode BSTFactory(int top,int depth) {
BinaryNode root=new BinaryNode(null,null,top);
BinaryNode leftChild,rightChild;
if(depth==0){
return root;
}
if(depth==1){
//create 2 children left and right
leftChild=new BinaryNode(null,null,top-1);
rightChild=new BinaryNode(null,null,top+1);
root=new BinaryNode(rightChild,leftChild,top);
return root;
}
if(depth>1){
leftChild=BSTFactory(top-1,depth-1);
rightChild=BSTFactory(top+1,depth-1);
root=new BinaryNode(rightChild,leftChild,top);
return root;
}
return root;
}
First of all, the two parameters of your method depend on each other. For example, BSTFactory(1,3) can't be a full binary tree with a minimal node of 1, since if the root already contains the minimal node, the left sub-tree must be empty (unless you allow negative values in your tree, which is not clear from your question, since you seem to want the tree to store integers starting from 1).
Therefore, I would suggest a wrapper method that would accept only the depth, and calculate the matching root node. We'll see how the two parameters are related later.
Now let's look at some small full binary trees to figure out the recursion :
Depth 0
1
Depth 1
2
1 3
Depth 2
4
2 6
1 3 5 7
Depth 3
8
4 12
2 6 10 14
1 3 5 7 9 11 13 15
What can we learn from these examples?
If we are creating a full binary search tree of depth n :
The root would be 2^n
The left sub-tree will be rooted at root - 2^(n-1)
The right sub-tree will be rooted at root + 2^(n-1)
Therefore, the recusion should be :
public static BinaryNode BSTFactory(int root, int depth)
{
BinaryNode leftChild,rightChild;
if (depth==0){
return new BinaryNode(null,null,root);
} else {
leftChild=BSTFactory(root-Math.pow(2,depth-1),depth-1);
rightChild=BSTFactory(root+Math.pow(2,depth-1),depth-1);
return new BinaryNode(rightChild,leftChild,root);
}
}
Note that in order for this to work (i.e. that your minimal node would be 1), you must call the method with a root and depth such that root=2^depth. To ensure that, lets define a wrapper method :
public static BinaryNode BSTFactory(int depth)
{
return BSTFactory (Math.pow(2^depth),depth);
}
If you call the two parameter method with arbitrary root and depth, you can get binary trees such as :
BSTFactory (6,1)
6
5 7
BSTFactory (1,2)
1
-1 3
-2 0 2 4
There are still full binary trees, but their minimal value is not 1.
Related
I am working on a leetcode problem where I am asked to check whether or not a Binary Search Tree is valid. So far, my solution only passes 58 out 75 test cases. Any pointers on where I went wrong and how to fix it?
Here is the question:
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
Example 1:
2
/ \
1 3
Input: [2,1,3]
Output: true
Example 2:
5
/ \
1 4
/ \
3 6
Input: [5,1,4,null,null,3,6]
Output: false
Explanation: The root node's value is 5 but its right child's value is 4.
Here is my Solution:
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidHelper(root);
}
public boolean isValidHelper(TreeNode root)
{
if(root == null)
return true;
isValidHelper(root.left);
if(root.left != null && !(root.left.val < root.val) || root.right != null && !(root.right.val > root.val))
return false;
isValidHelper(root.right);
return true;
}
}
Your program fails in cases like this:
5
3 7
1 6
because you only compare the value at the root of the subtrees.
I don't give a fix on purpose. You will learn more finding that out yourself.
Inorder: 3 2 1 5 4 6 8 9 7 11 10
Postorder: 1 2 3 4 5 6 9 11 10 7 8
I believe I am on the right track by taking the last postorder value as the root, finding that value in the Inorder list and splitting the tree to the left and the right of that value. From what I've been trying, I was able to come up with this result: It was not formatting correctly so I screenshot it.
Get the last element from the Postorder, this is your root element, then find that element in the Inorder and split the elements in left and right list giving you LEFT: "3 2 1 5 4 6" and RIGHT: "9 7 11 10" then walk the Postorder list and split it once you find the first number before the index of the root element in the Inorder list, in this case this is "6" so walk till 6 and this will give you "1 2 3 4 5 6" and the rest is "9 11 10 7". Then insert those lists in reverse order, e.g.: "6 5 4 3 2 1" and after that "7 10 11 9" this should give you the correct order of the tree.
It is a little tricky, maybe because contradicts a little the brain hemispheres ;-)
The parameters of interest are:
post: an array containing the postorder traversal
lp: left index of post array
rp: right index of post array
in: an array containing the inorder traversal
li: left index of in array
ri: riggh index of ìn array
The procedure is "naturally" recursive. At each recursion, the root always is post[rp]. That is the last visited node (in postorder).
So, the first thing to do is to know the index of the root in the array in. In order to compute that, we scan from li to ri and we search post[rp]. Let i the index of root in the array in. I assume that the tree does not have duplicated keys.
Given the index of root, then
i - li is the number of nodes in the left subtree
ri - i is the number of nodes in the right subtree
Now, in becomes naturally partitioned. The left subtree is between [li, i - 1] and the right subtree is between [i + 1, ri].
What I think is a little confuse is to determine where are the subtrees in post. The left subtree is between [lp, lp + (i - li) - 1] and the right is between [rp - (ri - i), rp - 1]. Take in account the numbers of nodes of each subtree expressed above (in the enumerated list).
With this knowledge we would be ready for designing an algorithm (I write in pseudo-C++, but I think it is very easy to translate to java):
Node * build_postorder(const vector<int> & post, long lp, long rp,
const vector<int> & in, long li, long ri)
{
if (lp > rp)
return nullptr; // we stop recursion when the tree is empty
Node * root = new Node(post[rp]); // Creates the root with key value post[rp]
int i = li;
for (; i <= ri; ++i) // search in inorder array the index of root
if (in[i] == post[rp])
break; // this line must always to execute it (if everything is oK)
LLINK(root) = build_postorder(post, lp, lp + (i - li) - 1, in, li, i - 1);
RLINK(root) = build_postorder(post, rp - (ri - i), rp - 1, in, i + 1, ri);
return root;
}
Good luck!
I have been trying to get this to work but while it works for majority of the input sometimes it gives the wrong output. I have spent some time debugging the code and it seems the problem is when i get a Node that is smaller than the root but bigger than the left node under the root.
How can I traverse the right sub-tree and still return the right key if no node in the right sub-tree is the floor node for that key?
Recall that if you do anything recursively, it can be transformed* into iteration.
Let's consider taking the floor of a well-formed BST, which should simply be the smallest element which is less than or equal to your key in the tree. All we have to do is traverse the tree to get it.
Let's implement it recursively so we can tease out a few important corollaries between iteration and recursion.
// Assuming non-null root node with method declaration
private Node floor(Node root, Key key, Node lowestNode) {
if(key.compareTo(root.getKey()) <= 0) {
if(root.getLeft() != null) {
return floor(root.getLeft(), key, lowestNode);
} else {
return root.compareTo(lowestNode) < 0 ? root : lowestNode;
}
} else {
if(root.getRight() != null) {
lowestRightNode.add(root);
return floor(root.getRight(), key, lowestNode);
} else {
return lowestNode;
}
}
Let's walk through the conditions for success.
If we compare a node to be less than or equal to our key value:
If we have a left child, there's something smaller. Traverse down the left half of the tree.
Otherwise, we're at the floor - which means we're at the node whose value is less than or equal to our key. Return it.
Otherwise (our node has a value greater than our key):
If we have a right child, there's a chance that our work isn't done yet (something's smaller). We'd like to keep it around since we could step off of the tree, so let's store it, then traverse down the right half of the tree.
Otherwise, we've fallen off of the tree. Return the smallest element we've kept track of.
An example may look something like this:
9
/ \
3 14
/ \
1 2
With a key of 12:
Compare with 9. We're larger. Store 9 in our lowest node variable, recurse right.
Compare with 14. We're smaller, but we don't have a left child. We compare the value 14 to 9 and 9 is smaller, so we return the node with 9.
If we want to convert this into iteration, then think about your starting point, your conditional check, and your incrementation steps.
Starting point: A non-null node
Conditional check:
key.compareTo(root.getKey()) <= 0
root.getLeft() != null
continue
root.compareTo(lowestRightNode) < 0 ? root : lowestRightNode
terminal
else
root.getRight() != null
store temp value and continue
return lowestRightNode
terminal
Pay close attention to your continuation conditions, and what other work you'd have to do to keep track of the lowest node you've seen so far (only for the right-hand side, that is).
*: Some recursive operations are more painful to convert than others, of course.
I'm having trouble with swapping nodes between two binary trees.
I'm trying to swap the current node with the passed node in the tree, but I can't figure out how; I can only seem to swap the parents of the nodes, but not the nodes themselves.
Can anyone give me some direction?
public void swap(Node node) {
if(this.equals(this.parent.leftChild)){
Node tempNodeR = node.parent.rightChild;
System.out.println("Is a left child");
node.parent.rightChild = this.parent.leftChild;
this.parent.leftChild = tempNodeR;
}
else{
Node tempNodeL = node.parent.leftChild;
System.out.println("Is a right child");
node.parent.leftChild = this.parent.rightChild;
this.parent.rightChild = tempNodeL;
}
}
Calling node2.swap(node4):
Given Tree:
1 3
/ \
2 4
Resulting Tree (unchanged):
1 3
/ \
2 4
Expected Tree:
1 3
/ \
4 2
For each node, the node has a reference to its parent and the parent has a reference to that child. So if you're going to swap two nodes, you need to update four references.
Tree
1 3
/ \
2 4
So here...
1 has a reference that points to 2 that you want to point to 4.
2 has a reference to 1 that should point to 3.
4 has a reference to 3 that should point to 1.
3 has a reference to 4 that should point to 2.
Hope that helps.
I am trying to split a binary search tree at the root in Java. I have no idea how to go about this. The recursive call is what is mostly confusing me. Below is the pseudocode that I was given. When x is greater than T (the tree to be split), am I going to call split(R.key, R.right, L, R)? Am I on the right track? This is the only function in the project that is confusing me.
Thanks in advance.
void split( int x, bst T, bst L, bst R) /* assuming x is not in T */
{
if T is null, make L and R null
else if x < T.key
set R = T /* all keys at the root and in right subtree are greater than x */
recursively split T's left subtree into L and R’s left subtree
/* some keys in T's left subtree are greater than x, other may be less than x */
else /* x is greater than T.key */
set L = T
recursively split T's right subtree into L's right subtree and R
}
It is important that you must have a binary ordered tree, such that Left < Root < Right for every subtree. Also, there is no node in the left subtree such that node > Root, and no node in the right subtree such that node < Root. Balancing (that all subtrees are same depth +- 1) is not needed.
It is like a dicomotical search; if the value to split by is greater than your current root, you are sure that it is greater than all nodes in the left subtree (because of the previous restriction). So, in order to search which of the nodes of the tree are bigger, you only need to check the nodes to the right. Likewise, if the value to split by is less than the value of root, it is also less than the values of all the nodes of the right subtree, and you must check more finely in the left tree.
In order to see it clearly, I suggest you to draw this tree (no spacing here)
8
4 12
3 6 10 14
1 2 5 7 9 11 13 15
, set several sample split values, and mark which nodes would remain in the new tree.