I have been preparing for an interview and came across this question:
Q. Build a binary tree from level order & inorder tree traversal.
Can someone guide me in this regard. I have been struggling with formulating the algorithm for long time now.
Here is the code I wrote:
struct node * buildLevelInTree(int * in, int * Level, int inStart, int inEnd, int level){
static int levelIndex=0;
struct node * root=newNode(Level[levelIndex++]);
//node has no child
if(inStart==inEnd)
return root;
int inIndex=searchIndex(in,inStart,inEnd,root->data);//search index of root in inorder traversal
//Note the use of level to take the next root from level order traversal
root->left=buildLevelInTree(in,Level,inStart,inIndex-1,2*level+1);
if(root->left!=NULL)
root->right=buildLevelInTree(in,Level,inIndex+1,inEnd,2*level+2);
else
root->right=buildLevelInTree(in,Level,inIndex+1,inEnd,2*level+1);
return root;
}//end of buildLevelInTree
Thanks a ton!
Finally, I could debug my code and work it out to function correctly. Next approach will be to optimise this algorithm. Suggestions to optimise this code (space wise) are welcomed.
/*
Algorithm Hint:
A
/ \
B C
/ \ / \
D E F G
inorder order will be DBEAFCG
and leve order will be ABCDEFG
From the level order, we know that A is the root, then check inorder, we further know DBE is left subtree and FCG is right subtree. to construct left subtree, from level order, we know left subtree's level order is BDE(find DBE's order in level order after A), we call the method to construct left subtree with inorder DBE and level order BDE.
*/
struct node * buildLevelInTree(int * in, int in_size, int *level, int l_size){
if(in_size==0 || l_size==0)
return NULL;
int in_index,l_count,r_count;
in_index=searchIndex(in,0,in_size,level[0]);
l_count=in_index;r_count=in_size-in_index-1;
struct node* root=newNode(level[0]);
int *in_left=makeInorder_left(in,in_size,in_index);
int *in_right=makeInorder_right(in,in_size,in_index);
int *level_left=makeLevel_left(level,l_size,in_left,l_count);
int *level_right=makeLevel_right(level,l_size,in_right,r_count);
root->left=buildLevelInTree(in_left,l_count,level_left,l_count);
root->right=buildLevelInTree(in_right,r_count,level_right,r_count);
return root;
}//end of buildLevelInTree
//Helping function for buildLevelInTree
int * makeInorder_right(int *in, int in_size, int pivot){
if(in==NULL)
return NULL;
int *in_right;
in_right=(int *)malloc(sizeof(int)*(in_size-pivot-1));
int i=pivot+1;
for(;i<in_size;i++)
in_right[i-pivot-1]=in[i];
return in_right;
}
//Helping function for buildLevelInTree
int *makeLevel_left(int *level, int lv_size, int * in_left, int inleft_size){
if(in_left == NULL || level == NULL)
return NULL;
int *level_left;
level_left=(int *)malloc(sizeof(int)*inleft_size);
int i=0;
int temp;
for(i=0;i<inleft_size;i++){
temp=searchLevel(level,lv_size,in_left[i]);
level_left[i]=temp;//searchLevel(level, lv_size, in_left[i]);
}
level_left=sort(level_left,inleft_size);
for(i=0;i<inleft_size;i++){
temp=level[level_left[i]];
level_left[i]=temp;//level[level_left[i]];
}
return level_left;
}
//Helping function for buildLevelInTree
int *makeLevel_right(int *level, int lv_size, int * in_right, int inright_size){
if(in_right == NULL || level == NULL)
return NULL;
int *level_right;
level_right=(int *)malloc(sizeof(int)*inright_size);
int i=0;
for(i=0;i<inright_size;i++)
level_right[i]=searchLevel(level, lv_size, in_right[i]);
level_right=sort(level_right,inright_size);
for(i=0;i<inright_size;i++)
level_right[i]=level[level_right[i]];
return level_right;
}
//Helping function for buildLevelInTree
int * sort(int *a,int n)
{
int i,j,k,temp;
for(i=1;i< n;i++)
{
for(j=0;j< n-1;j++)
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
return a;
}
//Helping function for buildLevelInTree
int searchLevel(int *level, int lv_size, int value){
int i=0;
for(i=0;i<lv_size;i++){
if(level[i]==value)
return i;
}
return -1;
}
Related
I am confused, the function binaryTreeToBST that has the below-mentioned operations and function call. Why are we not adding time complexities of each called function instead of taking only the time complexity of sort (step 3 below)?
countNodes
Creating temp array arr[] that stores inorder traversal of the tree. (takes O(n) )
sort the temp array arr[]. This step takes O(nlogn) time.
Again do inorder traversal to convert BT to BST(takes O(n) )
/* A program to convert Binary Tree to Binary Search Tree */
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node structure */
struct node {
int data;
struct node* left;
struct node* right;
};
/* A helper function that stores inorder traversal of a tree rooted
with node */
void storeInorder(struct node* node, int inorder[], int* index_ptr)
{
// Base Case
if (node == NULL)
return;
/* first store the left subtree */
storeInorder(node->left, inorder, index_ptr);
/* Copy the root's data */
inorder[*index_ptr] = node->data;
(*index_ptr)++; // increase index for next entry
/* finally store the right subtree */
storeInorder(node->right, inorder, index_ptr);
}
/* A helper function to count nodes in a Binary Tree */
int countNodes(struct node* root)
{
if (root == NULL)
return 0;
return countNodes(root->left) + countNodes(root->right) + 1;
}
// Following function is needed for library function qsort()
int compare(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
/* A helper function that copies contents of arr[] to Binary Tree.
This function basically does Inorder traversal of Binary Tree and
one by one copy arr[] elements to Binary Tree nodes */
void arrayToBST(int* arr, struct node* root, int* index_ptr)
{
// Base Case
if (root == NULL)
return;
/* first update the left subtree */
arrayToBST(arr, root->left, index_ptr);
/* Now update root's data and increment index */
root->data = arr[*index_ptr];
(*index_ptr)++;
/* finally update the right subtree */
arrayToBST(arr, root->right, index_ptr);
}
// This function converts a given Binary Tree to BST
void binaryTreeToBST(struct node* root)
{
// base case: tree is empty
if (root == NULL)
return;
/* Count the number of nodes in Binary Tree so that
we know the size of temporary array to be created */
int n = countNodes(root);
// Create a temp array arr[] and store inorder traversal of tree in arr[]
int* arr = new int[n];
int i = 0;
storeInorder(root, arr, &i);
// Sort the array using library function for quick sort
qsort(arr, n, sizeof(arr[0]), compare);
// Copy array elements back to Binary Tree
i = 0;
arrayToBST(arr, root, &i);
// delete dynamically allocated memory to avoid memory leak
delete[] arr;
}
/* Utility function to create a new Binary Tree node */
struct node* newNode(int data)
{
struct node* temp = new struct node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
/* Utility function to print inorder traversal of Binary Tree */
void printInorder(struct node* node)
{
if (node == NULL)
return;
/* first recur on left child */
printInorder(node->left);
/* then print the data of node */
printf("%d ", node->data);
/* now recur on right child */
printInorder(node->right);
}
/* Driver function to test above functions */
int main()
{
struct node* root = NULL;
/* Constructing tree given in the above figure
10
/ \
30 15
/ \
20 5 */
root = newNode(10);
root->left = newNode(30);
root->right = newNode(15);
root->left->left = newNode(20);
root->right->right = newNode(5);
// convert Binary Tree to BST
binaryTreeToBST(root);
printf("Following is Inorder Traversal of the converted BST: \n");
printInorder(root);
return 0;
}
I'm looking at this question on leetcode. Given two arrays, inorder and preorder, you need to construct a binary tree. I get the general solution of the question.
Preorder traversal visits root, left, and right, so the left child would be current preorder node index + 1. From that value, you can then know how many nodes are on the left of the tree using the inorder array. In the answers, the formula used to get the right child is "preStart + inIndex - inStart + 1".
I don't want to memorize the formula so I'm wondering if there is a proof for this? I went through the discussion board there, but I'm still missing a link.
For Python Only
In Python we can also use pop(0) for solving this problem, even though that's inefficient (it would pass though).
For inefficiency we can likely use deque() with popleft(), however not on LeetCode, because we don't have control over the tree.
class Solution:
def buildTree(self, preorder, inorder):
if inorder:
index = inorder.index(preorder.pop(0))
root = TreeNode(inorder[index])
root.left = self.buildTree(preorder, inorder[:index])
root.right = self.buildTree(preorder, inorder[index + 1:])
return root
For Java and C++, that'd be a bit different just like you said (don't have the proof) but maybe this post would be just a bit helpful:
public class Solution {
public static final TreeNode buildTree(
final int[] preorder,
final int[] inorder
) {
return traverse(0, 0, inorder.length - 1, preorder, inorder);
}
private static final TreeNode traverse(
final int preStart,
final int inStart,
final int atEnd,
final int[] preorder,
final int[] inorder
) {
if (preStart > preorder.length - 1 || inStart > atEnd) {
return null;
}
TreeNode root = new TreeNode(preorder[preStart]);
int inorderIndex = 0;
for (int i = inStart; i <= atEnd; i++)
if (inorder[i] == root.val) {
inorderIndex = i;
}
root.left = traverse(preStart + 1, inStart, inorderIndex - 1, preorder, inorder);
root.right = traverse(preStart + inorderIndex - inStart + 1, inorderIndex + 1, atEnd, preorder, inorder);
return root;
}
}
C++
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>
#include <unordered_map>
using ValueType = int;
static const struct Solution {
TreeNode* buildTree(
std::vector<ValueType>& preorder,
std::vector<ValueType>& inorder
) {
std::unordered_map<ValueType, ValueType> inorder_indices;
for (ValueType index = 0; index < std::size(inorder); ++index) {
inorder_indices[inorder[index]] = index;
}
return build(preorder, inorder, inorder_indices, 0, 0, std::size(inorder) - 1);
}
private:
TreeNode* build(
std::vector<ValueType>& preorder,
std::vector<ValueType>& inorder,
std::unordered_map<ValueType, ValueType>& inorder_indices,
ValueType pre_start,
ValueType in_start,
ValueType in_end
) {
if (pre_start >= std::size(preorder) || in_start > in_end) {
return nullptr;
}
TreeNode* root = new TreeNode(preorder[pre_start]);
ValueType pre_index = inorder_indices[preorder[pre_start]];
root->left = build(preorder, inorder, inorder_indices, pre_start + 1, in_start, pre_index - 1);
root->right = build(preorder, inorder, inorder_indices, pre_start + 1 + pre_index - in_start, pre_index + 1, in_end);
return root;
}
};
Code translated to C from Wirth's book is following
void quicksort(int *array, int left, int right)
{
int v=array[(left+right)/2];
int i,j,x;
i=left;
j=right;
do {
while (array[i]<v) i++;
while (array[j]>v) j--;
if (i<=j) {
x=array[i];
array[i]=array[j];
array[j]=x;
i++;
j--;
}
} while (i<=j);
if (j>left) quicksort(array, left, j);
if (i<right) quicksort(array, i, right);
}
but that uses arrays - my stab at doubly linked lists (node structure here ):
void partitonSort(node **head,node **tail)
{
node *v; // here I want to use first or last element as pivot
node *i,*j;
do
{
while(i->key < v->key) i = i->next;
while(j->key > v->key) j = j->prev;
if(/*what boolean expression should I use here*/)
{
/*Is it necessary to replace swap operation
with insert and delete operations and
how to do it */
i = i->next;
j = j->prev;
}
}
while(/*what boolean expression should I use here*/);
if(/*what boolean expression should I use here*/)
partitonSort(head,&j);
if(/*what boolean expression should I use here*/)
partitonSort(&i,tail);
}
I left questions in the code comments:
- Should I replace swap operation with insert and delete
 and how to do this
- What boolean expressions I should use
Here is my concise solution with detailed comments:
/* a node of the doubly linked list */
struct Node
{
int data;
struct Node *next;
struct Node *prev;
};
/* A utility function to swap two elements */
void swap ( int* a, int* b )
{ int t = *a; *a = *b; *b = t; }
// A utility function to find last node of linked list
struct Node *lastNode(Node *root)
{
while (root && root->next)
root = root->next;
return root;
}
/* Considers last element as pivot, places the pivot element at its
correct position in sorted array, and places all smaller (smaller than
pivot) to left of pivot and all greater elements to right of pivot */
Node* partition(Node *l, Node *h)
{
// set pivot as h element
int x = h->data;
// similar to i = l-1 for array implementation
Node *i = l->prev;
// Similar to "for (int j = l; j <= h- 1; j++)"
for (Node *j = l; j != h; j = j->next)
{
if (j->data <= x)
{
// Similar to i++ for array
i = (i == NULL)? l : i->next;
swap(&(i->data), &(j->data));
}
}
i = (i == NULL)? l : i->next; // Similar to i++
swap(&(i->data), &(h->data));
return i;
}
/* A recursive implementation of quicksort for linked list */
void _quickSort(struct Node* l, struct Node *h)
{
if (h != NULL && l != h && l != h->next)
{
struct Node *p = partition(l, h);
_quickSort(l, p->prev);
_quickSort(p->next, h);
}
}
// The main function to sort a linked list. It mainly calls _quickSort()
void quickSort(struct Node *head)
{
// Find last node
struct Node *h = lastNode(head);
// Call the recursive QuickSort
_quickSort(head, h);
}
Yes but I prefer to change links instead of data
Here is pseudocode
PartitionSort(L)
if head[L] != tail[L] then
//Choose the pivot node, first node or last node is the option
pivot := tail[L]
//Partition step, we distribute nodes of the linked list into three sublists
curr := head
while curr != NULL do
if key[curr] < key[pivot] then
pushBack(curr,Less)
else if key[curr] = key[pivot] then
pushBack(curr,Equal)
else
pushBack(curr,Greater)
end if
end if
curr := next[curr]
end while
// Here me make sure that we partitioned linked list correctly
// We should set next of tail pointers and prev of head pointers to NULL
//Now we do recursive calls on sublists with keys not equal to the pivot key
PartitionSort(Less)
PartitionSort(Greater)
// Now we concatenate sublists
if tail[Less] != NULL then
next[tail[Less]] := head[Equal]
else
head[Less] := head[Equal]
end if
if head[Equal] then
prev[head[Equal]] = tail[Less]
tail[Less] = tail[Equal]
end if
if tail[Less] != NULL then
next[tail[Less]] := head[Greater]
else
head[Less] := head[Greater]
end if
if head[Greater] then
prev[head[Greater]] = tail[Less]
tail[Less] = tail[Greater]
end if
L := Less
end if
Is there any difference, efficiency-wise, in using instance variables vs passing arguments by function calls during recursion? For example, I was recently doing a problem on Leetcode which asked to:
Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST.
My solution and the most popular one by far is as follows: 46 ms according to Leetcode
class Solution {
public:
int sum = 0;
TreeNode* convertBST(TreeNode* root) {
if (root == NULL) return 0;
convertBST(root->right);
sum += root->val;
root->val = sum;
convertBST(root->left);
return root;
}
};
But why couldn't we also use the following solution, or does it matter? 59 ms runtime according to Leetcode
class Solution {
public:
TreeNode* convertBST(TreeNode* root, int* sum) {
if (root == NULL) return NULL;
convertBST(root->right, sum);
*sum += root->val;
root->val = *sum;
convertBST(root->left, sum);
return root;
}
TreeNode* convertBST(TreeNode* root) {
int sum = 0;
return convertBST(root, & sum);
}
};
Thanks
I was trying to familarize with the question of creating a tree given inorder and postorder traversal. I wrote the following code, but some thing is going wrong which i was unable to find out. Can someone help me on this?
Sample i/p :
int in[] = {4,10,3,1,7,11,8,2};
int post[] = {4,1,3,10,11,8,2,7};
public static TreeNode buildInorderPostorder( int post[], int n, int offset,Map<Integer,Integer> indexMap,int size) {
if (size <= 0) return null;
int rootVal = post[n-1];
int i = (indexMap.get(rootVal) - offset);
TreeNode root = new TreeNode(rootVal);
root.setLeft(buildInorderPostorder( post, i, offset,indexMap,i-offset));
root.setRight(buildInorderPostorder(post, n-1, offset+i,indexMap,n-1-i));
return root;
}
root.setRight seems to be wrong.offset shouldn't be offset+i, it should be offset+i+1:
root.setRight(buildInorderPostorder(post, n-1, offset+i+1,indexMap,n-1-i));