0% found this document useful (0 votes)
4 views31 pages

Tree

The document provides an in-depth explanation of tree data structures, detailing their hierarchical nature, key terms, properties, types, and implementations. It covers various tree types such as binary trees, AVL trees, red-black trees, and B-trees, along with traversal methods like inorder, preorder, postorder, and level order. Additionally, it includes code snippets for tree traversal and discusses the use cases of each traversal method.

Uploaded by

Safdar Ali Niazi
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
4 views31 pages

Tree

The document provides an in-depth explanation of tree data structures, detailing their hierarchical nature, key terms, properties, types, and implementations. It covers various tree types such as binary trees, AVL trees, red-black trees, and B-trees, along with traversal methods like inorder, preorder, postorder, and level order. Additionally, it includes code snippets for tree traversal and discusses the use cases of each traversal method.

Uploaded by

Safdar Ali Niazi
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 31

A tree is also one of the data structures that represent hierarchical data.

Suppose we want
to show the employees and their positions in the hierarchical form then it can be represented
as shown below:

The above tree shows the organization hierarchy of some company. In the above structure,
john is the CEO of the company, and John has two direct reports named as Steve and Rohan.
Steve has three direct reports named Lee, Bob, Ella where Steve is a manager. Bob has two
direct reports named Sal and Emma. Emma has two direct reports named Tom and Raj.
Tom has one direct report named Bill. This particular logical structure is known as a Tree.
Its structure is similar to the real tree, so it is named a Tree. In this structure, the root is at
the top, and its branches are moving in a downward direction. Therefore, we can say that the
Tree data structure is an efficient way of storing the data in a hierarchical way.

Let's understand some key points of the Tree data structure.

• A tree data structure is defined as a collection of objects or entities known as nodes


that are linked together to represent or simulate hierarchy.
• A tree data structure is a non-linear data structure because it does not store in a
sequential manner. It is a hierarchical structure as elements in a Tree are arranged in
multiple levels.
• In the Tree data structure, the topmost node is known as a root node. Each node
contains some data, and data can be of any type. In the above tree structure, the node
contains the name of the employee, so the type of data would be a string.
• Each node contains some data and the link or reference of other nodes that can be
called children.

Some basic terms used in Tree data structure.

Let's consider the tree structure, which is shown below:

• Root: The root node is the topmost node in the tree hierarchy. In other words, the
root node is the one that doesn't have any parent. In the above structure, node
numbered 1 is the root node of the tree. If a node is directly linked to some other
node, it would be called a parent-child relationship.
• Child node: If the node is a descendant of any node, then the node is known as a child
node.
• Parent: If the node contains any sub-node, then that node is said to be the parent of
that sub-node.
• Sibling: The nodes that have the same parent are known as siblings.
• Leaf Node:- The node of the tree, which doesn't have any child node, is called a leaf
node. A leaf node is the bottom-most node of the tree. There can be any number of
leaf nodes present in a general tree. Leaf nodes can also be called external nodes.
• Internal nodes: A node has atleast one child node known as an internal
• Ancestor node:- An ancestor of a node is any predecessor node on a path from the
root to that node. The root node doesn't have any ancestors. In the tree shown in the
above image, nodes 1, 2, and 5 are the ancestors of node 10.
• Descendant: The immediate successor of the given node is known as a descendant of
a node. In the above figure, 10 is the descendant of node 5.

Properties of Tree data structure

Recursive data structure: The tree is also known as a recursive data structure. A tree
can be defined as recursively because the distinguished node in a tree data structure is
known as a root node. The root node of the tree contains a link to all the roots of its
subtrees. The left subtree is shown in the yellow color in the below figure, and the right
subtree is shown in the red color. The left subtree can be further split into subtrees shown
in three different colors. Recursion means reducing something in a self-similar manner. So,
this recursive property of the tree data structure is implemented in various applications.

• Number of edges: If there are n nodes, then there would n-1 edges. Each arrow in
the structure represents the link or path. Each node, except the root node, will have
at least one incoming link known as an edge. There would be one link for the parent-
child relationship.
• Depth of node x: The depth of node x can be defined as the length of the path from
the root to the node x. One edge contributes one-unit length in the path. So, the depth
of node x can also be defined as the number of edges between the root node and the
node x. The root node has 0 depth.
• Height of node x: The height of node x can be defined as the longest path from the
node x to the leaf node.

Types of Tree data structure

The following are the types of a tree data structure:

General tree: The general tree is one of the types of tree data structure. In the general tree,
a node can have either 0 or maximum n number of nodes. There is no restriction imposed
on the degree of the node (the number of nodes that a node can contain).
There can be n number of subtrees in a general tree. In the general tree, the subtrees are
unordered as the nodes in the subtree cannot be ordered.

Binary tree: Here, binary name itself suggests two numbers, i.e., 0 and 1. In a binary tree,
each node in a tree can have utmost two child nodes. Here, utmost means whether the node
has 0 nodes, 1 node or 2 nodes.

Binary Search tree:


Every node in the left subtree must contain a value less than the value of the root node, and
the value of each node in the right subtree must be bigger than the value of the root node.

AVL tree

It is one of the types of the binary tree, or we can say that it is a variant of the binary search
tree. AVL tree satisfies the property of the binary tree as well as of the binary search tree.
It is a self-balancing binary search tree that was invented by Adelson Velsky Lindas. Here,
self-balancing means that balancing the heights of left subtree and right subtree. This
balancing is measured in terms of the balancing factor.

We can consider a tree as an AVL tree if the tree obeys the binary search tree as well as a
balancing factor. The balancing factor can be defined as the difference between the height
of the left subtree and the height of the right subtree. The balancing factor's value must be
either 0, -1, or 1; therefore, each node in the AVL tree should have the value of the balancing
factor either as 0, -1, or 1.

Red-Black Tree

The red-Black tree is the binary search tree. The prerequisite of the Red-Black tree is that
we should know about the binary search tree. In a binary search tree, the value of the left-
subtree should be less than the value of that node, and the value of the right-subtree should
be greater than the value of that node. As we know that the time complexity of binary search
in the average case is log2n, the best case is O(1), and the worst case is O(n).

When any operation is performed on the tree, we want our tree to be balanced so that all the
operations like searching, insertion, deletion, etc., take less time, and all these operations will
have the time complexity of log2n.

The red-black tree is a self-balancing binary search tree. AVL tree is also a height balancing
binary search tree then why do we require a Red-Black tree. In the AVL tree, we do not
know how many rotations would be required to balance the tree, but in the Red-black tree,
a maximum of 2 rotations are required to balance the tree. It contains one extra bit that
represents either the red or black color of a node to ensure the balancing of the tree.

Splay tree

The splay tree data structure is also binary search tree in which recently accessed element
is placed at the root position of tree by performing some rotation operations. Here, splaying
means the recently accessed node. It is a self-balancing binary search tree having no explicit
balance condition like AVL tree.

It might be a possibility that height of the splay tree is not balanced, i.e., height of both left
and right subtrees may differ, but the operations in splay tree takes order of logN time where
n is the number of nodes.

Splay tree is a balanced tree but it cannot be considered as a height balanced tree because
after each operation, rotation is performed which leads to a balanced tree.

Treap

Treap data structure came from the Tree and Heap data structure. So, it comprises the
properties of both Tree and Heap data structures. In Binary search tree, each node on the left
subtree must be equal or less than the value of the root node and each node on the right
subtree must be equal or greater than the value of the root node. In heap data structure, both
right and left subtrees contain larger keys than the root; therefore, we can say that the root
node contains the lowest value.

In treap data structure, each node has both key and priority where key is derived from the
Binary search tree and priority is derived from the heap data structure.

The Treap data structure follows two properties which are given below:
• Right child of a node>=current node and left child of a node <=current node (binary
tree)
• Children of any subtree must be greater than the node (heap)

B-tree

B-tree is a balanced m-way tree where m defines the order of the tree. Till now, we read that
the node contains only one key but b-tree can have more than one key, and more than 2
children. It always maintains the sorted data. In binary tree, it is possible that leaf nodes can
be at different levels, but in b-tree, all the leaf nodes must be at the same level.

If order is m then node has the following properties:

• Each node in a b-tree can have maximum m children


• For minimum children, a leaf node has 0 children, root node has minimum 2 children
and internal node has minimum ceiling of m/2 children. For example, the value of m
is 5 which means that a node can have 5 children and internal nodes can contain
maximum 3 children.
• Each node has maximum (m-1) keys.

The root node must contain minimum 1 key and all other nodes must contain atleast ceiling
of m/2 minus 1 keys.

Implementation of Tree

The tree data structure can be created by creating the nodes dynamically with the help of the
pointers. The tree in the memory can be represented as shown below:
In programming, the structure of a node can be defined as:

struct node
{
int data;
struct node *left;
struct node *right;
}
Inorder Traversal

Inorder traversal visits the node in the order: Left -> Root -> Right

Use of Inorder Traversal:

The case of binary search trees (BST),


Inorder traversal gives nodes in non-
decreasing order.

Inorder traversal can be used to evaluate


arithmetic expressions stored in expression
trees.

Recursive Inorder Iterative Inorder


vector<int> ans; vector<int> inorderTraversal(TreeNode* root) {
void ino(TreeNode * node){
stack<TreeNode*> st;
if(node == NULL) return;
TreeNode *node = root;
vector<int> inorder;
ino(node -> left);
ans.push_back(node -> data); while(true){
ino(node -> right); if(node != NULL){
st.push(node);
node = node -> left;
} }
else{
vector<int> getInOrderTraversal(TreeNode *root) if(st.empty() == true) break;
{ node = st.top();
st.pop();
// Write your code here.
inorder.push_back(node -> val);
ino(root); node = node -> right;
return ans; }
} }

return inorder;

}
Preorder Traversal

Preorder traversal visits the node in the order: Root -> Left -> Right

Uses of Preorder Traversal:

Preorder traversal is used to create


a copy of the tree.

Preorder traversal is also used to


get prefix expressions on an
expression tree.

Recursive Preoder Iterative Preorder


void pre(TreeNode *root , vector<int> &result){ vector<int> preorderTraversal(TreeNode* root) {
if(root == NULL){ vector<int> ans;
return; stack<TreeNode *> st;
} st.push(root);
result.push_back(root->data); if(root == NULL){
pre(root->left , result); return ans;
pre(root -> right , result); }
}
while(!st.empty()){
vector<int> getPreOrderTraversal(TreeNode
TreeNode * temp = st.top();
*root)
ans.push_back(temp -> val);
{
st.pop();
// Write your code here.
if(temp -> right) {
vector<int> result;
st.push(temp->right);
pre(root,result);
}
return result;
if(temp -> left){
st.push(temp -> left);

} }}
return ans; }
Postorder Traversal

Postorder traversal visits the node in the order:


Uses of Postorder Traversal:
Left -> Right -> Root
Postorder traversal is used to delete
the tree.

Postorder traversal is also useful to


get the postfix expression of an
expression tree.

Postorder traversal can help in


garbage collection algorithms,
particularly in systems where
manual memory management is
used.

Recursive Postorder Iterative Postorder


vector<int> ans; vector<int> postorderTraversal(TreeNode* root)
void post(TreeNode * node){ {
if(node == NULL) return;
vector<int> ans;
stack<TreeNode*> st;
post(node -> left); st.push(root);
post(node -> right); if(root == NULL) return ans;;
ans.push_back(node -> data); while(!st.empty()){
TreeNode * temp = st.top();
st.pop();
} ans.push_back(temp->val);
if(temp->left != NULL){
vector<int> postorderTraversal(TreeNode *root) st.push(temp->left);
}
{
if(temp->right != NULL){
// Write your code here. st.push(temp->right);
post(root); }
return ans; }
} reverse(ans.begin() , ans.end());
return ans;

}
Level Order Traversal

Level Order Traversal visits all nodes present in the same level completely before visiting the
next level.

Uses of Level Order:

Level Order Traversal is mainly used as


Breadth First Search to search or process
nodes level-by-level.

Level Order traversal is also used for Tree


Serialization and Deserialization.

Return vector<int> Easy Return vector<vector<int>> Medium

Level Order Traversal - Naukri Code 360 Binary Tree Level Order Traversal - LeetCode

vector<int> getLevelOrder(BinaryTreeNode<int> vector<vector<int>> levelOrder(TreeNode* root) {


*root) vector<vector<int>> ans;
{ if(root == NULL){
// Write your code here. return ans;
vector<int> ans; }
if(root == NULL) { queue<TreeNode*> q;
return ans; q.push(root);
} while(!q.empty()){
int size = q.size();
queue<BinaryTreeNode<int> *> q;
vector<int> level;
q.push(root);
for(int i=0; i<size; i++){
while(!q.empty()){
TreeNode* temp = q.front();
q.pop();
BinaryTreeNode<int> *temp = q.front();
level.push_back(temp->val);
q.pop();
if(temp->left != NULL) {
ans.push_back(temp->val);
q.push(temp->left);
if(temp -> left != NULL){
q.push(temp-> left); }

} if(temp->right != NULL){
if(temp -> right != NULL){ q.push(temp->right);
q.push(temp-> right); }
} }
ans.push_back(level);
} }

return ans; return ans;


}
}

Questions

104. Maximum Depth of Binary Tree

int maxDepth(TreeNode* root) {


if(root == NULL) return 0;

return 1 + max(maxDepth(root->left) , maxDepth(root->right));

110. Balanced Binary Tree (the idea is to use any traversal along with height function)

void ino(TreeNode* root , bool &ans){


if(root == NULL) return;
ino(root->left , ans);
int lh = height(root->left);
int rh = height(root->right);
if(abs(lh-rh) > 1) {
ans = false;
}
ino(root->right , ans);
}
int height(TreeNode* root){
if(root == NULL) return 0;
return 1 + max(height(root->left) , height(root->right));
}
bool isBalanced(TreeNode* root) {
if(root == NULL) return true;
bool ans = true;
ino(root,ans);
return (ans);
}

543. Diameter of Binary Tree(the idea is to use any traversal and calculate lh + rh for each
node by using height function)

O(n2) in worst case

int height(TreeNode* root){


if(root == NULL) return 0;
return 1 + max(height(root->left) , height(root->right));
}
void ino(TreeNode* root , int &maxi){
if(root == NULL) return;
ino(root->left , maxi);
int lh = height(root->left);
int rh = height(root->right);
maxi = max(maxi, lh + rh);
ino(root->right, maxi);
}
int diameterOfBinaryTree(TreeNode* root) {
int maxi = 0;
ino(root, maxi);
return maxi;
}
O(n) Solution

We already have access to lh and rh in height function , so no need of traversal function.just


carry another variable maxi in height function

int height(TreeNode* root , int &maxi){


if(root == NULL) return 0;
int lh = height(root->left, maxi);
int rh = height(root->right, maxi);
maxi = max(maxi , lh + rh);
return 1 + max(lh,rh);
}

124. Binary Tree Maximum Path Sum

Har node pe do options hain ya to wo answer bane ya sahi path batade. Agar answer banna
hai to leftsum ko jodo , right sum lo aur root ki value ko aur kyunki aisi bht si node hain to
sabka maximum lelo like this maxi = max(maxi , root->val + leftsum + rightsum);

Aur agar answer nhin banna hai to return kardo root ki value plus max of left sum , right sum

return root->val + max(leftsum,rightsum);

int maxpath(TreeNode* root , int & maxi){


if(root == nullptr) return 0;
int leftsum = maxpath(root->left , maxi);
int rightsum = maxpath(root->right , maxi);
if(leftsum < 0) leftsum =0;
if(rightsum < 0) rightsum =0;
maxi = max(maxi , root->val + leftsum + rightsum);
return root->val + max(leftsum,rightsum);
}
103. Binary Tree Zigzag Level Order Traversal

(just use level order with an index that track end of each level and use if(ind %2 == 0) then
reverse the level then push)

Boundary Traversal of Binary Tree

First add left side →

TreeNode<int> * temp = root->left;


while(temp != nullptr){
if(!(temp -> left == nullptr && temp -> right == nullptr))
boundaries.push_back(temp -> data);
if(temp -> left != nullptr) temp = temp -> left;
else temp = temp -> right;
}

Then leaf using inorder traversal

void inorder(TreeNode<int> *root , vector<int> &boundaries){


//left root right
if(root == nullptr) return;

inorder(root->left, boundaries);
if(root->left == nullptr && root->right==nullptr){
boundaries.push_back(root->data);
}
inorder(root -> right , boundaries);
}

Then right side in reverse →

vector<int> tempo;
temp = root->right;
while(temp != nullptr){
if(!(temp -> left == nullptr && temp -> right == nullptr))
tempo.push_back(temp -> data);
if(temp->right != nullptr) temp = temp -> right;
else temp = temp -> left;
}
reverse(tempo.begin(), tempo.end());
for(int i=0; i<tempo.size(); i++){
boundaries.push_back(tempo[i]);
}

987. Vertical Order Traversal of a Binary Tree

Its more like a data structure question which involve multiset , queue , map;, the idea is
simple use level order traversal and keep putting element in their desired position.

vector<vector<int>> verticalTraversal(TreeNode* root) {


queue<pair<TreeNode* , pair<int,int>>> q;
q.push({root,{0,0}});
map<int,map<int,multiset<int>>> mp;
while(!q.empty()){
auto el = q.front();
q.pop();
TreeNode* node = el.first;
int x = el.second.first;
int y = el.second.second;
mp[x][y].insert(node -> val);
if(node->left){
q.push({node->left, {x-1,y+1}});
}
if(node->right){
q.push({node->right, {x+1,y+1}});
}
}
vector<vector<int>> ans;
for(auto p: mp){
vector<int> col;
for(auto xx: p.second){
col.insert(col.end(),xx.second.begin(),xx.second.end());
}
ans.push_back(col);
}
return ans;
}
Top View Of Binary Tree

( {first node in every vertical line → top view}

use concept of vertical line and store in a map if a line is visited , if it is visited then don’t pick
element from that line and use map also not unordered_map because we need element of
farthest line first that is we need element in line wise like , first we need element from line -
3 then -2 , -1 , 0 , 1, 2) so on , so map stores in sorted order that’s why use map.

vector<int> getTopView(TreeNode<int> *root)


{
// Write your code here.
queue<pair<TreeNode<int>* , int>> q;
q.push({root,0});
map<int , int> mp;
while(!q.empty()){
auto el = q.front();
q.pop();
TreeNode<int>* node = el.first;
int line = el.second;
if(mp.find(line) == mp.end()) {
mp[line] = node -> data;
}
if(node -> left != nullptr) q.push({node->left , line-1});
if(node -> right != nullptr) q.push({node->right, line+1});
}
vector<int> ans;
for(auto it: mp){
ans.push_back(it.second);
}
return ans;
}

Bottom View Of Binary Tree

(last element in each vertical line )

vector<int> bottomView(TreeNode<int> * root){


// Write your code here.
queue<pair<TreeNode<int> * , int>> q;
q.push({root,0});
map<int,int> mp;
while(!q.empty()){
auto el = q.front();
q.pop();
TreeNode<int>* node = el.first;
int line = el.second;
mp[line] = node -> data;
if(node -> left != nullptr) q.push({node->left , line-1});
if(node -> right != nullptr) q.push({node->right, line+1});
}
vector<int> ans;
for(auto it: mp){
ans.push_back(it.second);
}
return ans;

199. Binary Tree Right Side View

We can do this by level order traversal as well as with reverse pre order traversal Level order
traversal is not recommended due to its space complexity. The idea is to pick only one
element from each level. So ham ek data structure bana lenge aur har level pe ek baar hi
insert ho iske liye if(level == res.size()) res.push_back( root -> val); ye condition lagayenge.
Jab same level pe left ki taraf se aayega to data structure me kai elements honge aur ye
condition match nhin hogi , isliye enter nhin hoga naya element.

void reverse_pre_order(TreeNode* root , int level , vector<int> &res){


if(root == nullptr) return;
if(level == res.size()) res.push_back( root -> val);
reverse_pre_order(root -> right , level + 1 , res);
reverse_pre_order(root -> left , level + 1 , res);
}

vector<int> rightSideView(TreeNode* root) {


vector<int> res;
reverse_pre_order(root,0,res);
return res;
}

101. Symmetric Tree

When moving left in one sub tree , move right in another subtree to compare the values.

bool helper(TreeNode* root1, TreeNode* root2){


if(root1 != nullptr && root2 != nullptr){
bool a = helper(root1 -> left , root2 -> right);
bool b = helper(root1 -> right , root2 -> left);
if((root1 -> val == root2 -> val) && a && b)
return true;
else return false;
}
else if(root1 == nullptr && root2 == nullptr) return true;
else return false;
}

bool isSymmetric(TreeNode* root) {


if(root == nullptr) return true;
return helper(root -> left , root -> right);
}

Root to a given node path {important concept}

bool hasPath(Node *root, vector<int>& arr, int x)


{
if (!root)
return false;
arr.push_back(root->data);
if (root->data == x)
return true;

if (hasPath(root->left, arr, x) ||
hasPath(root->right, arr, x))
return true;
arr.pop_back();
return false;
}

236. Lowest Common Ancestor of a Binary Tree

Har node ya to null return kar rahi hai ya agar no mil jata hai to wo number return kar rahi hai.

Lca(4,7) →

6 node donon taraf se null return kar rahi hai, 7 node 7 return kar rahi hai kyunki lca(4,7)
nikalna hai. 5 node men ek taraf null hai ek taraf 7 , to 5 node bhi 7 return karegi.

TreeNode* trav(TreeNode* root , TreeNode* p , TreeNode * q){


if(root == NULL || root == p || root == q) return root;
TreeNode* left = trav(root->left , p , q);
TreeNode* right = trav(root->right , p , q);
if(left == NULL) return right;
else if(right == NULL) return left;
else return root;
}

662. Maximum Width of Binary Tree

(ismen har node ko index dete hain if parent index is i then left child 2*i + 1 and right 2*i + 2)
but ye karne se bht badi values aati hain isliye har level pe ek fixed value minus kar dete hain
taki phir values range men aayen.
int widthOfBinaryTree(TreeNode* root) {
if(!root) return 0;

int width = 1;
queue<pair<TreeNode*,int>> q;

q.push({root,0});

while(!q.empty()){

int size = q.size();

int start_index = q.front().second;

int end_index = q.back().second;

width = max(width , end_index - start_index + 1);

for(int i=0; i<size; i++){

auto node_pair = q.front();

TreeNode* node = node_pair.first;

int index = node_pair.second - start_index;

q.pop();

if(node -> left != nullptr) q.push({node -> left , 2LL * index + 1});

if(node -> right != nullptr) q.push({node -> right , 2LL * index + 2});

return width;

}
Check for Children Sum Property in a Binary Tree

1. int fn(Node *root){


2. if(root == nullptr || (root -> left == nullptr && root->right == nullptr) ) return 1;
3.
4. int left_sum = 0;
5. int right_sum = 0;
6.
7. if(root -> left) left_sum = root->left->data;
8. if(root -> right) right_sum = root->right->data;
9.
10. if((root -> data == left_sum + right_sum) && fn(root->left) && fn(root->right)) return 1;
11. else return 0;
12.
13.
14. }
15.

863. All Nodes Distance K in Binary Tree

Input: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, k = 2

Output: [7,4,1]
Explanation: The nodes that are a distance 2 from the target node (with value 5) have values
7, 4, and 1.

Sol:

1. Mark parents of each node so we can go upward


2. From the target node go to up , left , right and mark them visited and increase distance
by
3. When distance = k, break

void markparent(TreeNode* root,


unordered_map<TreeNode*, TreeNode*>& parent_info) {
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* temp = q.front();
q.pop();
if (temp->left) {
parent_info[temp->left] = temp;
q.push(temp->left);
}
if (temp->right) {
parent_info[temp->right] = temp;
q.push(temp->right);
}
}
}

vector<int> distanceK(TreeNode* root, TreeNode* target, int k) {


unordered_map<TreeNode*, TreeNode*> parent_info;
markparent(root, parent_info);
unordered_map<TreeNode*, bool> visited;
queue<TreeNode*> q;
q.push(target);
visited[target] = true;
int d = 0;
while (!q.empty()) {
int size = q.size();
if(d++ == k) break;
for (int i = 0; i < size; i++) {
TreeNode* temp = q.front();
q.pop();

if (temp->left && !visited[temp->left]) {


q.push(temp->left);
visited[temp->left] = true;
}
if (temp->right && !visited[temp->right]) {
q.push(temp->right);
visited[temp->right] = true;
}

if (parent_info[temp] && !visited[parent_info[temp]]) {


q.push(parent_info[temp]);
visited[parent_info[temp]] = true;
}

}
}
vector<int> ans;
while (!q.empty()) {
ans.push_back(q.front()->val);
q.pop();
}
return ans;
}

2385. Amount of Time for Binary Tree to Be Infected

Same as above in place of breaking d , increase count everytime , no break condition.

void mark_parents(TreeNode* root , unordered_map<TreeNode*, TreeNode*> &mp ,


TreeNode* &target , int start){
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
TreeNode* temp = q.front();
if(temp -> val == start){
target = temp;
}
q.pop();
if(temp -> left) {
mp[temp-> left] = temp;
q.push(temp->left);
}
if(temp -> right) {
mp[temp-> right] = temp;
q.push(temp->right);
}
}
}

int amountOfTime(TreeNode* root, int start) {


unordered_map<TreeNode* , TreeNode*> mp;
TreeNode* target;
mark_parents(root,mp,target,start);
unordered_map<TreeNode* , bool> visited;
queue<TreeNode*> q;
q.push(target);
visited[target] = true;
int d = 0;
while(!q.empty()){
int size = q.size();
d++;
for(int i=0; i<size; i++){
TreeNode * temp = q.front();
q.pop();

if(temp -> left && !visited[temp -> left]){


visited[temp -> left] = true;
q.push(temp -> left);
}
if(temp -> right && !visited[temp -> right]){
visited[temp -> right] = true;
q.push(temp -> right);
}
if(mp[temp] && !visited[mp[temp]]){
q.push(mp[temp]);
visited[mp[temp]] = true;
}

}
return d-1;
}

Requirements needed to construct a Unique Binary Tree → inorder +


preorder/postorder

1. TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder){


2. // Create a map to store indices of elements in the inorder traversal
3. map<int, int> inMap;
4. // Populate the map with indices of elements in the inorder traversal
5. for(int i = 0; i < inorder.size(); i++){
6. inMap[inorder[i]] = i;
7. }
8. // Call the private helper function to recursively build the tree
9. TreeNode* root = buildTree(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1,
inMap);
10. return root;
11. }
12. // Recursive helper function to build the tree
13. TreeNode* buildTree(vector<int>& preorder, int preStart, int preEnd,
14. vector<int>& inorder, int inStart, int inEnd, map<int, int>& inMap){
15. // Base case: If the start indices exceed the end indices, return NULL
16. if(preStart > preEnd || inStart > inEnd){
17. return NULL;
18. }
19. // Create a new TreeNode with value at the current preorder index
20. TreeNode* root = new TreeNode(preorder[preStart]);
21. // Find the index of the current root value in the inorder traversal
22. int inRoot = inMap[root->val];
23. // Calculate the number of elements in the left subtree
24. int numsLeft = inRoot - inStart;
25. // Recursively build the left subtree
26. root->left = buildTree(preorder, preStart + 1, preStart + numsLeft,
27. inorder, inStart, inRoot - 1, inMap);
28. // Recursively build the right subtree
29. root->right = buildTree(preorder, preStart + numsLeft + 1, preEnd,
30. inorder, inRoot + 1, inEnd, inMap);
31. // Return the current root node
32. return root;
33. }
34.
297. Serialize and Deserialize Binary Tree

string serialize(TreeNode* root) {


if(root == nullptr) return "";

string s = "";
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
TreeNode * temp = q.front();
q.pop();
if(temp == nullptr) s.append("#,");
else s.append(to_string(temp->val) + ',');
if(temp != nullptr) {
q.push(temp -> left);
q.push(temp -> right);
}
}
cout << s ;
return s;
}

// Decodes your encoded data to tree.


TreeNode* deserialize(string data) {
if(data.size() == 0) return nullptr;
stringstream s(data);
string str;
getline(s,str,',');
TreeNode * root = new TreeNode(stoi(str));
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
TreeNode * node = q.front();
q.pop();

getline(s,str,',');
if(str == "#"){
node -> left = nullptr;
}
else{
TreeNode * leftnode = new TreeNode(stoi(str));
node ->left = leftnode;
q.push(leftnode);
}

getline(s,str,',');
if(str == "#"){
node -> right = nullptr;
}
else{
TreeNode* rightnode = new TreeNode(stoi(str));
node -> right = rightnode;
q.push(rightnode);
}
}
return root;
}

Morris Traversal (important)

https://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-
stack/

114. Flatten Binary Tree to Linked List

void flatten(TreeNode* root) {


TreeNode* curr = root;
while(curr != nullptr){
if(curr -> left != nullptr){
TreeNode * pred = curr -> left;
while(pred -> right) pred = pred -> right;
pred -> right = curr -> right;
curr -> right = curr -> left;
curr -> left = nullptr;
}
curr = curr -> right;
}
}

Dp on Trees (Aditya Verma)

General Syntax of recursive fn for dp on trees

Int solve(Node* root , int & res  this variable should be passed by address and it will store
the answer to all dp on tree problem)

{ If(root == nullptr) {
Base Return 0
Condition }

Hypothesis (is part men


Int l = solve(root->left)
kaam kaise hua uspe
Int r = solve(root->right)
sawal mat karna)

Induction Int temp = calculate temp ans (1 + max(l,r))


Int ans = max(temp , relation)
Res = max(res,temp)
Basically each node can decide whether it is the
answer or it need to pass its value to some other node

} Return temp;  yahan temp bhejna hai kyunki usko


answer nhin banna

You might also like