diameter of a Binary tree recursive approach - c++

I am trying to find diameter using recursion ,I am confused with recursion
some of the test cases I tried I got correct answer at some point
Integer overflow occured But Below author's solution was accepted with same data types
My approach:
For every node, length of longest path which pass it = MaxDepth of its left subtree + MaxDepth of its right subtree.
My question is whats wrong with my implementation
class Solution {
public:
int mx = 0;
int solve(TreeNode* root) {
if (root == NULL)return 0;
int leftheight = diameterOfBinaryTree(root->left) + 1;
int rightheight = diameterOfBinaryTree(root->right) + 1;
mx = max(mx, leftheight + rightheight);
return max(leftheight, rightheight);
}
int diameterOfBinaryTree(TreeNode* root) {
solve(root);
return mx;
}
};
Authors approach: same approach but different recursion implementation
class Solution {
public:
int maxdiadepth = 0;
int dfs(TreeNode* root) {
if (root == NULL) return 0;
int leftdepth = dfs(root->left);
int rightdepth = dfs(root->right);
if (leftdepth + rightdepth > maxdiadepth) maxdiadepth = leftdepth + rightdepth;
return max(leftdepth + 1, rightdepth + 1);
}
int diameterOfBinaryTree(TreeNode* root) {
dfs(root);
return maxdiadepth;
}
};

In the working implementation, the recursive dfs call returns the max depth of the subtree.
In your implementation, the recursive diameterOfBinaryTree call returns the currently accumulated approximation to the diameter. You assign it to variables named leftheight and rightheight - that's misleading; the value is not, in fact, the height of the left or right sub-tree.

Consider the case when you hit a leaf node or the case where you have only one node. Your algorithm returns 2, which is incorrect. This problem arises because you compute the height by adding one to the left / right subtree, no matter what.
To fix this, add one when you return the height, like so: max(leftheight, rightheight) + 1
Btw, when you recursively call, you should do solve(root->left) or solve(root->right) and not diameterOfBinaryTree(root->left) :P

Related

Build minimum height BST from a sorted std::list<float> with C++

I'm having trouble writing the code to build minimum height BST from a sorted std::list.
For the node class:
class cBTNode
{
private:
cBTNode* m_LeftChild;
cBTNode* m_RightChild;
float m_Data;
}
For the BST class:
class cBTNodeTree
{
private:
cBTNode* m_Root;
public:
void LoadBalancedMain(std::list<float>& ls);
void LoadBalanced(std::list<float>& ls, cBTNode* root);
}
Implementation: (basically my method is to find the middle element of the list ls, put that into the root, put all the elements smaller than the middle element into ls_left, and all the elements bigger than it into ls_right. Then recursively build up the left and right subtree by recursively calling the same function on ls_left and ls_right)
void cBTNodeTree::LoadBalancedMain(std::list<float>& ls)
{
LoadBalanced(ls, m_Root); // m_Root is the root of the tree
}
void cBTNodeTree::LoadBalanced(std::list<float>& ls, cBTNode* root)
{
// Stopping Condition I:
if (ls.size() <= 0)
{
root = nullptr;
return;
}
// Stopping Condition II:
if (ls.size() == 1)
{
root = new cBTNode(ls.front());
return;
}
// When we have at least 2 elements in the list
// Step 1: Locate the middle element
if (ls.size() % 2 == 0)
{
// Only consider the case of even numbers for the moment
int middle = ls.size() / 2;
std::list<float> ls_left;
std::list<float> ls_right;
int index = 0;
// Obtain ls_left consisting elements smaller than the middle one
while (index < middle)
{
ls_left.push_back(ls.front());
ls.pop_front();
index += 1;
}
// Now we reach the middle element
root = new cBTNode(ls.front());
ls.pop_front();
// The rest is actually ls_right
while (ls.size() > 0)
{
ls_right.push_back(ls.front());
ls.pop_front();
}
// Now we have the root and two lists
cBTNode* left = root->GetLeftChild();
cBTNode* right = root->GetRightChild();
if (ls_left.size() > 0)
{
LoadBalanced(ls_left, left);
root->SetLeftChild(left);
}
else
{
left = nullptr;
}
if (ls_right.size() > 0)
{
LoadBalanced(ls_right, right);
root->SetRightChild(left);
}
else
{
right = nullptr;
}
}
}
My Question: Somehow I found that actually none of the elements has been inserted into the tree. For example, if I check the value of m_Root, the root of the tree, I got an error because it's still nullprt. I'm not sure where did I go wrong? I hope it's some stupid pointer mistake because I haven't slept well. (I'm pretty sure the 'new cBTNode(ls.front())' line works)
BTW although I have written a dozen functions for the BST, I'm still struggling with BST recursion. I noticed that in all the textbooks that I read, for the linked list version of BST, the insertion ALWAYS need a helper function that return a pointer to a node. I begin to feel that I don't actually understand the things going on behind the recursion...
1:
void cBTNodeTree::LoadBalanced(std::list<float>& ls, cBTNode* root)
Here cBTNode* root is passed by value.
Instead, you should pass by reference & or cBTNode** (pointer to a pointer).
Passing by reference would be simple, you won't need to change anything except the function signature.
void cBTNodeTree::LoadBalanced(std::list<float>& ls, cBTNode*& root)
Notice & before root in above statement.
2:
if (ls_right.size() > 0)
{
LoadBalanced(ls_right, right);
root->SetRightChild(left);
}
You are setting right child to left root which is not what you desire.
3:
cBTNode* left = root->GetLeftChild();
cBTNode* right = root->GetRightChild();
These are unnecessary.
4:
if (ls.size() % 2 == 0)
No need for two separate cases.
You can achieve this by just appropriately setting middle:
int middle = (ls.size()-1) / 2;
You pass the pointer to the root by value. Pass it by reference instead by changing the signature of LoadBalanced() appropriately.

Algorithmic improvement for finding minimum sum in a Binary Search Tree

I wrote the following function to find out the minimum sum of any path in a Binary Search Tree:
int minSumPath(TreeNode* root) {
if(root==NULL)
return 0;
int sum = root->value;
if(root->left!=NULL && root->right!=NULL)
sum += min(minSumPath(root->left),minSumPath(root->right));
else
if(root->left==NULL)
sum += minSumPath(root->right);
else
sum += minSumPath(root->left);
return sum;
}
While the above code generates the correct output, I feel that I am not leveraging the fact that it is a Binary Search Tree (BST) and not just a Binary Tree.
In a BST the left child node is smaller than the root and right node, so logically we can only consider the left child nodes of each root; but what if the BST has only a single child on the right (with say value 10) and multiple child nodes on the left (with sum >10)?
In this case the minimum sum would be 10 (which is on the right).
How I would be able to leverage the BST property, if at all? Also, any other optimizations that I can use in my approach?
Note: Edited the code to resolve the error;
An informed search could help in some cases.
In the worst case, the computational cost is exactly the same of your algorithm.
As an example:
int minSumPathOpt(TreeNode* root) {
if(root == nullptr) return 0;
int sum = -1;
std::stack<std::pair<TreeNode*, int>> todo;
todo.push(std::make_pair(root, 0));
while(not todo.empty()) {
std::pair<TreeNode*, int> curr = todo.top();
todo.pop();
TreeNode *node = curr.first;
int part = curr.second + node->value;
if(sum == -1 || part < sum) {
if(!node->left && !node->right) {
sum = part;
} else {
if(node->right) todo.push(std::make_pair(node->right, part));
if(node->left) todo.push(std::make_pair(node->left, part));
}
}
}
return sum;
}
The basic idea is to track the current minimum while performing a DFS. This will give you the chance to prune entire subtrees whenever the sum of the values to their root are already greater than the current minimum.
Moreover, exploring the left tree before to look at the right one could help maximizing the result (no assurance indeed, but it's a good idea because of how BSTs are defined).
See a comparison of the two approaches on wandbox.
As you can see, the second function doesn't explore at all trees that are not promising.

Segment tree implementation

I was learning segment tree from this page : http://letuskode.blogspot.com/2013/01/segtrees.html
I am finding trouble to understand various fragments of code.I will ask them one by one.Any help will be appreciated.
Node declaration:
struct node{
int val;
void split(node& l, node& r){}
void merge(node& a, node& b)
{
val = min( a.val, b.val );
}
}tree[1<<(n+1)];
1.What will the split function do here ?
2.This code is used for RMQ . So I think that val will be the minimum of two segments and store it in some other segment.Where the value will be saved?
Range Query Function:
node range_query(int root, int left_most_leaf, int right_most_leaf, int u, int v)
{
//query the interval [u,v), ie, {x:u<=x<v}
//the interval [left_most_leaf,right_most_leaf) is
//the set of all leaves descending from "root"
if(u<=left_most_leaf && right_most_leaf<=v)
return tree[root];
int mid = (left_most_leaf+right_most_leaf)/2,
left_child = root*2,
right_child = left_child+1;
tree[root].split(tree[left_child], tree[right_child]);
//node l=identity, r=identity;
//identity is an element such that merge(x,identity) = merge(identity,x) = x for all x
if(u < mid) l = range_query(left_child, left_most_leaf, mid, u, v);
if(v > mid) r = range_query(right_child, mid, right_most_leaf, u, v);
tree[root].merge(tree[left_child],tree[right_child]);
node n;
n.merge(l,r);
return n;
}
1.What is the use of the array tree and what values will be kept there ?
2.What will this statement : tree[root].split(tree[left_child], tree[right_child]); do ?
3.What will those statements do ? :
node n;
n.merge(l,r);
return n;
Update and Merge Up functions:
I am not understanding those two functions properly:
void mergeup(int postn)
{
postn >>=1;
while(postn>0)
{
tree[postn].merge(tree[postn*2],tree[postn*2+1]);
postn >>=1;
}
}
void update(int pos, node new_val)
{
pos+=(1<<n);
tree[pos]=new_val;
mergeup(pos);
}
Also what should I write inside the main function to make this thing work?
Suppose I have an array A={2,3,2,4,20394,21,-132,2832} , How I can use this code to find RMQ(1,4)?
1.What will the split function do here ?
Nothing: the function body is empty. There may be some other implementation where an action is required. (See Example 3) And see answer to 2b
2.... Where the value will be saved?
In the "val" field of the class/struct for which "merge" is called.
1b.What is the use of the array tree and what values will be kept there ?
Array "node tree[...]" stores all the nodes of the tree. Its element type is "struct node".
2b.What will this statement : tree[root].split(tree[left_child], tree[right_child]); do ?
It calls split for the struct node that's stored at index root, passing the nodes of the split node's children to it. What it actually does to tree[root] depends on the implementation of "split".
3b.What will those statements do ? :
node n; // declare a new node
n.merge(l,r); // call merge - store the minimum of l.val, r.val into n.val
return n; // terminate the function and return n
I'll have to figure out the answers to your last Qs in the context of that code. Will take a little time.
Later
This should build a tree and do a range query. I'm not sure that the code on that page is correct. Anyway, the interface for range_query is not what you'd expect for easy usage.
int main(){
int a[] = { -132, 1, 2, 3, 4, 21, 2832, 20394};
for( int i = 0; i < 8; i++ ){
node x;
x.val = a[i];
update( i, x);
}
node y = range_query(0, 8, 15, 8 + 1, 8 + 4 );
}

getting the number of nodes in a binary search tree

So I'm working on a method that gets the number of nodes in a binary search tree, when I have 3 nodes, it gives me 3, but if I do 5 it gives me 4, what do I need to change?
int BinaryTree::size(int count, Node *leaf) const
{
if(leaf != NULL)//if we are not at a leaf
{
size(count + 1, leaf->getLeft());//recurisvly call the function and increment the count
size(count + 1, leaf->getRight());
}
else
{
return count;//return the count
}
}
int BinaryTree::size(Node *leaf) const
{
if(leaf == NULL) { //This node doesn't exist. Therefore there are no nodes in this 'subtree'
return 0;
} else { //Add the size of the left and right trees, then add 1 (which is the current node)
return size(leaf->getLeft()) + size(leaf->getRight()) + 1;
}
}
While this is a different approach, I find that is it easier to read through than what you had.
Other people have already chimed in with a correct algorithm. I'm just going to explain why your algorithm doesn't work.
The logic behind your algorithm seems to be: keep a running count value. If the leaf is null then it has no children so return the count, if the leaf is not null then recurse down the children.
This is backwards though. Because you're going to need to pass your int by reference, not value, and then not increment if it's null, increment if it's not null, and recurse.
So your original idea would work with some modifications, but Nick Mitchinson and arrows have a better way. This is your algorithm fixed so it works:
int BinaryTree::size(Node *leaf, int& count=0) const
{
if(leaf != NULL)//if we are not at a leaf
{
count++;
size(leaf->getLeft(), count);//recurisvly call the function and increment the count
size(leaf->getRight(), count);
}
return count;//return the count
}
But again, there are better ways to write this. And the other answers show them.
int BinaryTree::size(Node *n) const
{
if(!n)
return 0;
else
return size(n->getLeft()) + 1 + size(n->getRight());
}

Find nth smallest element in Binary Search Tree

I have written an algorithm for finding nth smallest element in BST but it returns root node instead of the nth smallest one. So if you input nodes in order 7 4 3 13 21 15, this algorithm after call find(root, 0) returns Node with value 7 instead of 3, and for call find(root, 1) it returns 13 instead of 4. Any thoughts ?
Binode* Tree::find(Binode* bn, int n) const
{
if(bn != NULL)
{
find(bn->l, n);
if(n-- == 0)
return bn;
find(bn->r, n);
}
else
return NULL;
}
and definition of Binode
class Binode
{
public:
int n;
Binode* l, *r;
Binode(int x) : n(x), l(NULL), r(NULL) {}
};
It is not possible to efficiently retrieve the n-th smallest element in a binary search tree by itself. However, this does become possible if you keep in each node an integer indicating the number of nodes in its entire subtree. From my generic AVL tree implementation:
static BAVLNode * BAVL_GetAt (const BAVL *o, uint64_t index)
{
if (index >= BAVL_Count(o)) {
return NULL;
}
BAVLNode *c = o->root;
while (1) {
ASSERT(c)
ASSERT(index < c->count)
uint64_t left_count = (c->link[0] ? c->link[0]->count : 0);
if (index == left_count) {
return c;
}
if (index < left_count) {
c = c->link[0];
} else {
c = c->link[1];
index -= left_count + 1;
}
}
}
In the above code, node->link[0] and node->link[1] are the left and right child of node, and node->count is the number of nodes in the entire subtree of node.
The above algorithm has O(logn) time complexity, assuming the tree is balanced. Also, if you keep these counts, another operation becomes possible - given a pointer to a node, it is possible to efficiently determine its index (the inverse of the what you asked for). In the code I linked, this operation is called BAVL_IndexOf().
Be aware that the node counts need to be updated as the tree is changed; this can be done with no (asymptotic) change in time complexity.
There are a few problems with your code:
1) find() returns a value (the correct node, assuming the function is working as intended), but you don't propagate that value up the call chain, so top-level calls don't know about the (possible) found element
.
Binode* elem = NULL;
elem = find(bn->l, n);
if (elem) return elem;
if(n-- == 0)
return bn;
elem = find(bn->r, n);
return elem; // here we don't need to test: we need to return regardless of the result
2) even though you do the decrement of n at the right place, the change does not propagate upward in the call chain. You need to pass the parameter by reference (note the & after int in the function signature), so the change is made on the original value, not on a copy of it
.
Binode* Tree::find(Binode* bn, int& n) const
I have not tested the suggested changes, but they should put you in the right direction for progress