Finding a node in a cloned tree using DFS - c++

I am trying the LeetCode problem1379. Find a Corresponding Node of a Binary Tree in a Clone of That Tree:
Given two binary trees original and cloned and given a reference to a node target in the original tree.
The cloned tree is a copy of the original tree.
Return a reference to the same node in the cloned tree.
Note that you are not allowed to change any of the two trees or the target node and the answer must be a reference to a node in the cloned tree.
This is my code:
class Solution {
public:
TreeNode* ans = NULL ;
TreeNode* getTargetCopy(TreeNode* original, TreeNode* cloned, TreeNode* target) {
// if(cloned == NULL){return cloned ;}
if(cloned == NULL){return cloned ;}
// if(cloned->val == target->val){
// return cloned ;
// }
if(cloned->val == target->val){
ans = cloned ;
}
// return getTargetCopy(original,cloned->left ,target) ;
// return getTargetCopy(original,cloned->right,target) ;
getTargetCopy(original,cloned->left ,target) ;
getTargetCopy(original,cloned->right,target) ;
return ans ;
}
};
The commented out part was my initial code but it returned wrong answer
Your input
[7,4,3,null,null,6,19]
3
Output
null
Expected
3
Help me understand the problem in my code

Some issues:
With these (now commented) lines:
return getTargetCopy(original,cloned->left ,target) ;
return getTargetCopy(original,cloned->right,target) ;
...execution would never get to that second line, as the first line would end the function.
These (now commented) lines:
if(cloned->val == target->val){
return cloned ;
}
...are fine: once you have found the target value, there is no need to do anything else in this function, and so it is fine to return the node. This is better than setting ans to that node and still make some (unnecessary) recursive call(s).
What is missing here is getting the value from the first recursive call, and deciding whether that call successfully found the target value or not. In case it found it, there is no more need for a second recursive call. In case it didn't find it, then the second recursive call is needed. Finally, the return value you get from either recursive call, should be returned back as the current function's return value.
So:
class Solution {
public:
TreeNode* getTargetCopy(TreeNode* original, TreeNode* cloned, TreeNode* target) {
if (cloned == nullptr || cloned->val == target->val) {
return cloned;
}
TreeNode *ans = getTargetCopy(original,cloned->left ,target) ;
if (ans != nullptr) {
return ans;
}
return getTargetCopy(original,cloned->right,target) ;
}
};

Related

Recursive function to return last node of a heap

I am trying to return the last node of a binary heap (implemented with pointers, not an array). Here, 'last' means the bottom-most node starting from the left in this case without two children, actually the node where I am supposed to append the new node to. The insert function will bind data to a new node for insertion, then call this function to return the last node, so I can add the new node either left of right depending on the child nodes present, or not.
The problem is that the right side of the tree is always empty, and never gets past the height after root's. Seems to stick on the leftmost side, because it reaches first the exit condition from every recursion call starting from left.
The recursive function checks first the node, returns 0 if no child, returns 1 if only left child and returns 2 in case of a node having two children. Here is the function :
template<typename T>
node<T> * heap<T>::find_insert_pos (node<T> *x, int &res) {
if(find_insert_poshelper(x, res) == 0) return x;
else if(find_insert_poshelper(x, res) == 1) return x;
else {
node<T> *a = find_insert_pos(x->left, res);
if(find_insert_poshelper(a, res) != 2) return a;
else return find_insert_pos(a, res);
node<T> *b = find_insert_pos(x->right, res);
if(find_insert_poshelper(b, res) != 2) return b;
else return find_insert_pos(b, res);
}
}
I've tried to figure it out, but insertion still goes wrong. The other functions used into insertion are more than triple checked.
(By the way, 'res' is passed by reference always in the chunk of code)
I have changed the logic behind the function. Instead of only validating for children per node, I validate now if the node evaluated had children, if it does then I validate one step further each of those children, left and right, to see if any of those grand-children have children themselves.
If they don't, I will loop this for the next level following the root level 0, jumping to level 1 and so on, until one of the children nodes does not contain two children, and returning x.left or x.right, depending the case.
-- Final edit --
Hard to think about a MRE since it was more about logic. The question was posted by someone in need of practice with recursion, and it happened. All the logic changed, even for sub-functions.
But it will be required to manually assign and narrow down until three levels are full (full meaning having two children) before calling this operation, which is checking three levels down. Having this done nicely I get a beautiful heap.
I can show an attempt to a MRE of how I implemented it to be able to find the bottom node to append a new node to, but not pure since I don't put the code from the 'insert' function, which is part iterative (first three levels) and part recursive (that was the original question, to find the parent node for the new node to insert). How the insert operation goes, I create a new node dynamically and then I search for the parent node where I need to append new data to (the iterative part starts here until the 8th node of the tree is reached, path similar to BFS), then when the position is retrieved (that is, the pointer itself), I test whether for left or right insertion, as by the rules of the heap. Starting at the 8th node, the value of the parent node is set recursively as follows :
First the recursive function itself :
node * function_a (node *x, int &res) {
node *temp = function_b (x, res);
if(temp != ptr_null) return temp;
else {
if(x->L != ptr_null) function_a (x->L, res);
if(x->R != ptr_null) function_a (x->R, res);
return temp;
}
}
A sub-function :
node * function_b (node *x, int &res) {
node *a = x->L;
node *b = x->R;
int aL = function_c (a->L, res);
int aR = function_c (a->R, res);
int bL = function_c (b->L, res);
int bL = function_c (b->R, res);
if(aL != 2) return a->L;
else if(aR != 2) return a->R;
else if(bL != 2) return b->L;
else if(bR != 2) return b->R;
else return ptr_null;
}
And another :
int & function_c (node *x, int &res) {
if(x->L == ptr_null && x.R == ptr_null) return res = 0;
else if(x->L != ptr_null && x->R == ptr_null) return res = 1;
else return res = 2;
}
Since this is checking 3 levels down from x defined (in this case from the root) in function_a, I can't make it 100% recursive that way or I will get a segmentation fault. How can I improve my algorithm ?

Check if 2 nodes are adjacent in binary tree using linkedlish C++

Sorry for the bad English.
I'm creating a binary tree project by using a linked list in C++. And Im trying to make a boolean method to check if 2 nodes are adjacent or not?
And I'm trying to use the recursion method as I'm using the linked list to do this, but it seems I did it wrong.
Here is how I declare the Node
Struct Node{
string name;
int data;
Node *right, *left;
}
And here is how I declare the checking function:
bool checkadjacent(node* Node, string& u, string& v) {
if(!Node){
return false;
}
if (Node && Node->right) {
string current = Node->name;
string right = Node->right->name;
if (current == u && right == v)
return true;
else if (current == v && right == u)
return true;
}
if (Node && Node->left) {
string current = Node->name;
string left = Node->left->name;
if (current == u && left == v)
return true;
else if (current == v && left == u)
return true;
}
if (Node->left){
if(checkadjacent(Node->left, u, v)){
return true;
}
}
if (Node->right){
if(checkadjacent(Node->right, u, v)){
return true;
}
}
}
Note: "it seems I did it wrong" is not an explanation of how your code fials. Always describe what your code is SUPPOSED to do and what it is ACTUALLY doing.
Having said that, I'm assuming your code does not compile. I put together a (possibly non-comprehensive) list of errors and other problems with your code, aswell as a corrected version of your code. However, I would advise you to watch some tutorials about C++ (or C if you want, since your code is basically C code), because your code shows some serious misunderstandings and neglection. Apart from that, your basic idea seems correct except for the last bullet point in the following list.
List of problems:
It's struct not Struct (capitalization matters in C++). (This is necessary for correctness/syntax)
In the declaration of Node you capitalize the name of the Node. Later, you call it node and instead capitalize the name of the object which instantiates Node (to be consistent, I called the struct Node and it's instantiation node). (This is necessary for correctness/syntax)
First you check whether Node is actually pointing to a struct: if(!Node). This is good, but there is no need to check the same thing again later: if (Node && Node->right) and if (Node && Node->left) just leave out the first part in both conditions: if (node->right) and if (node->left). (This is for style)
Then you can also leave out the 3rd and 4th if statements and put their block into the 1st and 2nd if blocks respectively. (This is for style)
Do not declare the variables current, right and left inside the if blocks, instead declare them at the beginning of the function. (This is for style)
For the algorithm to work you have to return false if none of the if none of the if statements are executed (this is a guess; I did not test this and you WILL have to try that yourself). (This is necessary for correctness/semantics)
Here's the full code (note that I did NOT test this code, as your problem was clearly faulty syntax and not algorithm design.
bool checkadjacent(Node* node, string& u, string& v) {
string current, left, right;
if (!node) {
return false;
}
if (node->right) {
current = node->name;
right = node->right->name;
if (current == u && right == v)
return true;
else if (current == v && right == u)
return true;
// recursion
if (checkadjacent(node->right, u, v)) {
return true;
}
}
if (node->left) {
current = node->name;
left = node->left->name;
if (current == u && left == v)
return true;
else if (current == v && left == u)
return true;
// recursion
if (checkadjacent(node->left, u, v)) {
return true;
}
}
return false;
}
Also note:
I did not change the definition of Node.
Apart from string your code is just C code. In C++ you have the possibility to create a class for the binary tree which would be a lot more readable.
There are no linked lists in any parts of the code above (neither in the code you posted). The fact that the node have left and right child nodes, does not make it a linked list (in particular it's not a list because it is not 1-dimensional).
Again, I did NOT test this code; you can do that yourself.

How to parse a large tree?

recently I passed a programming interview where I had to create a method that returns the address of a node (belonging to a tree). The method takes an integer value as an argument.
My code worked on a small tree, but when searching a large tree (300,000 nodes) I got an error stating "cannot access address '0x.....'".
What should I do to fix this?
'''
struct Node
{
int value;
Node* left = nullptr;
Node* right = nullptr;
Node* find_node(int);
};
Node* Node::find_node(int v)// The function is working on small trees only
{
if(this->value == v) //comparing the the value inside the root with the function's argument
return this;
else if(this->value > v) //if v is smaller than the node's value, search the next left node
{
if(this->left == nullptr) //checking if the next node on the left exists
return nullptr; //null returned if there is no more nodes
else
return (this->left)->find_node(v); //Call the find_node function recursively on the left node
}
else if(this->value < v) //if v is bigger than the node's value, search the next right node
{
if(this->right == nullptr) //checking if the next node on the left exists
return nullptr; //null returned if there is no more nodes
else
return (this->right)->find_node(v);// Call the find_node function recursively on the right node
}
return nullptr;// If the value is not found
}
'''
Your code needs lots of activation records on the call stack for repetitive calls to find_node(v). And it may lead to overflow of the call stack.
To avoid it, you can use non-recursive versions of binary search that uses a loop instead. For more information, check this link.

Passing reference in C++

I am new to c++, from my understanding I have been thinking that if I pass address of a vector in a function call like fun(vector<int>&v) then the values don't get copied into a new vector of int, and any changes made will reflect back, and if in case of fun(vector<int> v) values get copied.
But when reading this link from geeksfrogeeks I realised that even if '&' is not there the changes on the vector made inside the function will retain after it ends.
here is the code:
/* This function prints all nodes that are distance k from a leaf node
path[] --> Store ancestors of a node
visited[] --> Stores true if a node is printed as output. A node may be k
distance away from many leaves, we want to print it once */
void kDistantFromLeafUtil(Node* node, int path[], bool visited[],
int pathLen, int k)
{
// Base case
if (node==NULL) return;
/* append this Node to the path array */
path[pathLen] = node->key;
visited[pathLen] = false;
pathLen++;
/* it's a leaf, so print the ancestor at distance k only
if the ancestor is not already printed */
if (node->left == NULL && node->right == NULL &&
pathLen-k-1 >= 0 && visited[pathLen-k-1] == false)
{
cout << path[pathLen-k-1] << " ";
visited[pathLen-k-1] = true;
return;
}
/* If not leaf node, recur for left and right subtrees */
kDistantFromLeafUtil(node->left, path, visited, pathLen, k);
kDistantFromLeafUtil(node->right, path, visited, pathLen, k);
}
The changes in the visited array made by one function are visible to the second call to KDistanceFromLeafUtil, without using '&', Is this similar to what happens in Java i.e referenced is copied ? Where did I go wrong in understanding it?
As " bool visited[]" is a pointer, it is indeed changed by your function.
If it were a bool or an int for instance, the copy or the argument would have been changed in the function but not the argument itself, and thus you would have seen no effect outside of your function.

Removing from a Binary Search Tree

I am trying to write a remove from a binary tree function. I'm kinda lost so I'm trying to handle it case by case, starting with if the value I'm trying to remove is in the root of the BST. To test my function, I am first calling a printcontents() function that prints all the contents of the tree, then I'm calling remove(8) [8 being the value in my root at the moment), and then calling printcontents() again. The way I'm doing it is by trying to replace the root with the "right-most" value in the left side of the tree. When I call printcontents the second time, it prints the new root value correctly, but when it continues printing the contents and reaches the point where that value used to be, it has a random long number "-572......"(although i don't think the number matters) and then my program crashes. I see my root's value is being replaced, but what happens afterwards??
Here's my remove function:
void BinarySearchTree::remove(int value) {
Node* tmp = head;
Node* tmp2 = head;
if (head->data == value && head->left != NULL) {
tmp=tmp->left;
while (tmp->right != NULL) {
tmp=tmp->right;
}
while (tmp2->right->right != NULL) {
tmp2=tmp2->right;
}
if (tmp->left == NULL) {
head->data = tmp->data;
tmp2->right = NULL;
delete tmp;
}
if (tmp->left != NULL) {
head->data = tmp->data;
tmp2->right = tmp->left;
delete tmp;
}
}
It's obviously incomplete, but I'm testing it to only handle the case in which the root is removed and replaced by the right-most value in the left side of the tree (assuming there is a left side, which there is), and I feel like logically it should be working, so perhaps it is when I "delete tmp" that things go wrong. I don't know whether posting my whole program will be necessary, but if so, let me know!
May I suggest that instead of writing out for root, why don't you treat the case as it is dealt with in CLRS : That is two distinct cases.
1. When node to be deleted is a leaf
2. When node to be deleted is non-leaf(in that case replace it with inorder successor/predecessor).
The root deletion obviously falls under the second case. This is just a suggestion.