Showing posts with label trees. Show all posts
Showing posts with label trees. Show all posts

BST with child count

You are given a special binary search tree where each node contains the
number of nodes in its child-trees in addition to the key.

Example:


(50,4)
/ \
(30,4) (70,2)
/ \ / \
(20,2) (40,0) (60,0) (80,0)
/ \
(10,0) (25,0)


Given, 10, 40, the required value is 3, since we have 20, 25, 30



Answer:


int FindCount(TreeNode* n, int min_val, int max_val)
{
if (n)
{
if ( n->val is between min_val and max_val )
return n->child_count - 2;
else if ( n->val < min_val )
return FindCount(n->right, min_val, max_val);
else
return FindCount(n->left, min_val, max_val);
}
return 0;
}

Merging two Binary Search Trees

Describe a method to merge two BSTs.

50
/ \
30 70
/ \ / \
20 40 60 80
/ \ \
10 25 90


30
/ \
15 45
\
20



Answer:

Probably the most efficient:
1. Create two array from the two trees by traversing in inorder: O(n+m) space + O(n+m) time
2. Merge the two arrays: O(n+m) time, O(n+m) space.
3. Create a balanced binary tree from this sorted array 1, O(n+m) time (see related solution)

Valid Binary Search Tree

Given a BST, give an approach to verify if it is a 'valid' BST. Code it.


Answer:

Solution I:

bool IsValidBST(TreeNode* n)
{
if(n)
{
bool isLeftValid = true;
bool isRightValid = true;
if( n->left )
{
if (n->left->val > n->val)
return false;
isLeftValid = isValidBST(n->left);

}
if( n->right)
{
if (n->right->val <= n->val)
return false;
isRightValid = isValidBST(n->right);
}
return isLeftValid && isRightValid;
}
return true;
}

n-ary trees

How do you represent an n-ary tree? Write a program to print the nodes
of such a tree in breadth first order.

Answer: using array of nodes, and use Q

Tree permutations

Write a program to calculate the different number of tree structures possible,
given n identical values.
For Example:

For one node, the tree is a trivial one node tree.
For two nodes, two combinations are possible:
O O
\ and /
O O

For three nodes :
O O O O O
/ / / \ \ \
O O O O O O
/ \ \ /
O O O O


Answer:



/*
For the above diagrams, we can see the recursive property,
i.e,
For given N nodes:
* One node becomes the root
* Divide the remaining N-1 nodes between left and right subtrees, and this can be
done as follows:
Left Subtree Right Subtree
0 N-1
1 N-2
2 N-3
... ...
N-1 0

Summing up the above combinations, to get the value of N,
The solution can be recursively defined as following:

{ 1 if n == 1 }
F(n) = { sigma( F(i) * F(n-i-1 ) where i = 0 to n-1 }

note that its F(i) * F(n-i-1) , product, not a sum because its a combinatorics problem,
If event A can be in m ways, and another event B can be done in n ways, then the total
possible events are (m x n)

Note that optimization can be achived by caching the results in the recursive call.


*/


#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
// the cache used to "cache the results in a recursive call"
vector cache;
size_t TreeCombinations(size_t n)
{
if ( (n == 1) || (n == 0) )
return cache[n];
// Check if the result was already computed
if ( cache[n] != 0 )
return cache[n];
else
{
int i = 0;
size_t combinations = 0;
//printf("{ %d \n", n);
for ( i =0 ; i <= n-1; ++i)
{
size_t tmp = TreeCombinations(i) * TreeCombinations(n-i-1);
//printf(" f(%d) * f(%d) = %d \n", i, n-i-1, tmp );
combinations += tmp;
}
//printf("}\n");
cache[n] = combinations;
}

return cache[n];
}

int main(int argc, char* argv[])
{
size_t n = atoi(argv[1]);
// initialize the cache
cache.reserve(n+1);
for ( int i = 0; i <= n; ++i )
{
cache[i] = 0;
}
cache[0] = 1;
cache[1] = 1;
// ----
return printf("Tree combinations for %d nodes = %d \n", n, TreeCombinations(n) );
}

Clumps in a Binary Tree

Assume that each node in a binary tree represents a color. A clump is defined as 3 or more adjacent nodes with same color.
Write an algorithm to determine the number of clumps.
For example:

R
/ \
R R
/ \ / \
B B R G
/ \ / \
B B G G
\
G
The Above tree has 3 clumps:
4 Adjacent Reds starting at the root.
4 adjacent Greens in the right subtree.
3 adjacent Blues in the left subtree.


Answer:

Here is the solution in C++:

#include
using namespace std;
// The colors of the tree
enum Color
{
Unknown,
Red,
Green,
Blue
};

struct TreeNode
{
Color color;
TreeNode* left;
TreeNode* right;

TreeNode(Color c, TreeNode* _left=0, TreeNode* _right=0):
color(c), left(_left), right(_right){}
};

void CountClumps(TreeNode* node, Color parentColor, size_t &curCount, size_t &clumpCount)
{
if( node )
{
if (node->color != parentColor)
{
/* The color of the current node is not equal to the
* parent node's color, then we dont increase the curCount, but start a new
* clumpCount */
size_t _curCount = 1; // 1 because of the current node color
CountClumps(node->left, node->color, _curCount, clumpCount);
CountClumps(node->right, node->color, _curCount, clumpCount);
if ( _curCount >= 3 )
++clumpCount;
}
else
{
/* increase the curCount ( which signifies the nodes with same color )
* and let the parent decide about the clump, and traverse the left and
* right subtrees
* */
++curCount;
CountClumps(node->left, node->color, curCount, clumpCount);
CountClumps(node->right, node->color, curCount, clumpCount);
}
}
}

int main(int argc, char* argv[])
{
// The left subtree
TreeNode *n1 = new TreeNode(Green,0,0);
TreeNode *n2 = new TreeNode(Green,0,n1);
TreeNode *n3 = new TreeNode(Green,0,0);
TreeNode *n4 = new TreeNode(Green,n3,n2);

TreeNode *n5 = new TreeNode(Red,0,0);
TreeNode *n6 = new TreeNode(Red,n5,n4);

// The right subtree
TreeNode *n7 = new TreeNode(Blue, 0,0);
TreeNode *n8 = new TreeNode(Blue, 0,0);
TreeNode *n9 = new TreeNode(Blue, n7,n8);
TreeNode *n10 = new TreeNode(Blue, 0, 0);
TreeNode *n11 = new TreeNode(Blue, n10, n9);

// The Root
TreeNode *root = new TreeNode(Red, n11, n6);

size_t curCount = 0;
size_t clumpCount = 0;

CountClumps( root, Unknown, curCount, clumpCount );

cout << "Clumps " << clumpCount << endl;

// set the left subtree to null
curCount = 0;
clumpCount = 0;
root->left = 0;
CountClumps( root, Unknown, curCount, clumpCount );

cout << "Clumps " << clumpCount << endl;

// set the right subtree to null
curCount = 0;
clumpCount = 0;
root->right= 0;
root->left = n11;
CountClumps( root, Unknown, curCount, clumpCount );

cout << "Clumps " << clumpCount << endl;

// Sorry forgot to release the memory of the TreeNode :D
return clumpCount;
}


Balanced Tree detection

Implement a algorithm to check if a tree is balanced, given its root node. i.e. "no two leaf nodes should differ in distance from the root by more than one". use the function prototype- bool IsBalanced(node *root)

3
/ \
8 8
/ \ /
5 5 7


Answer:


Solution 1:
Using Level Order traversal,


bool IsBalanced(Node *root)
{
Queue q;
size_t prev_depth = 0;
// We add the node, and the depth at which it
// occurs
q.enqueue( make_pair(root,0) );
while ( !q.isempty() )
{
pair node_depth_info = q.dequque();
Node* node = node_depth_info.first;
size_t cur_node_depth = node_depth_info.second;
if ( !node->left && !node->right )
{
// leaf!
if (prev_leaf_depth != cur_node_depth)
{
// previous leaf depth is not same as the current one
return false;
}
prev_leaf_depth = cur_node_depth;
}
// Add the children
if ( node->left )
q.enqueue( make_pair(node->left, cur_node_depth + 1) );
if ( node->right)
q.enqueue( make_pair(node->right, cur_node_depth + 1) );
}
return true; // hurray!
}


Solution 2:

Do a traversal, pass the depth of prev tree node and current depth info to next traversal


bool __isBalanced(Node *root, size_t &prev_tree_depth, size_t &cur_depth)
{
if ( root )
{
if ( !root->left && !root->right )
{
bool isLeftBalanced, isRightBalanced;
if(!prev_tree_depth) prev_tree_depth = cur_depth; // first time init
else
{
if (cur_depth != prev_tree_depth) return false; // does not match
prev_tree_depth = cur_depth; // update
}
}
cur_depth += 1;
isLeftBalanced = __isBalanced(root->left, prev_tree_depth, cur_depth);
if ( isLeftBalanced )
isRightBalanced = __isBalanced(root->right, prev_tree_depth, cur_depth);
else
return false;
return isLeftBalanced && isRightBalanced;
}
return true;
}

bool isBalanced(Node *root)
{
size_t prev_tree_depth = 0, cur_depth = 1;
return __isBalanced(root, prev_tree_depth, cur_depth );
}


Maximum depth of a tree

Write algo to find the max depth of a binary tree.
Answer:


size_t MaxDepth(Node *root)
{
if(root)
{
return max( MaxDepth(root->left) , MaxDepth(root->right) ) + 1;
}
return 0;
}

Find lowest value in BST >= value

Find the lowest valued node in a Binary Search Tree (BST) greater than
or equal to a a certain value.


30
/ \
20 50
/ / \
15 40 60
/ \
35 46
\
47



Solution 1:
O(n) solution:

/*
* Do a infix traversal of the BST and the moment we get
* a node such that >= given value we have the answer.
* */

void InfixTraversal(Node* root, int value, Node** n)
{
if(root)
{
InfixTraversal(root->left);
if (root->value >= value)
{
*n = root;
}
InfixTraversal(root->right);
}
}

Solution 2:
O(log(n)) solution:

/*
* Use the property of the tree, i.e values on the right > root and
* values on the left < root.
* */

void FindNode(Node *root, int value, Node **n)
{
if(root)
{
// move right if the node val is less than reqd value.
if (root->val < value ) return FindNode(root->right, value, n);
// the condition is met and the current value is better than than
// previously set value.
if ( (root->val >= value) && (*n && (*n->value > root->value)) )
{
*n = root;
}
// check in the right subtree for a better value.
return FindNode(root->left, value, n);
}

/* Let the value = 46 and trace for the above tree */


Serializing a Binary Tree

Design an algorithm and write code to serialize a binary tree. Discuss
various solutions

Answer:

Possible answer : Traverse the tree in inorder and store the numbers onto the disk.
then read the numbers and use the logic to create a binary tree from a sorted array.
Like this we will be creating a balanced tree when we deserialize the tree.

Tree, Linked list creation problem

Imagine you have an unbalanced binary search tree. Now make a linked list of all the nodes at every depth(level) of the tree. Assume every node along with a left and a right pointer also has a next pointer. To make the linked list inside the binary tree for every level, the next pointer of the first node at every depth should point to the next node at the same depth in the tree and so on for the other nodes. What is the complexity of your algorithm.

10
/ \
5 20
/ \ /
3 6 15

~~~~ TO ~~~~
10
/ \
5 ----> 20
/ \ /
3---> 6-->15



Answer:

Here is a solution of time and spacecomplexity O(n)
Here we do a breadth first search using a queue, and maintain the previous
node and its depth to create the linked list.

struct Node
{
int val;
Node *next;
Node *left;
Node *right;
};

void LinkifyTree(Node* root)
{
Queue q;
// contains the node and the depth at which the node occurs.
typedef pair NodeInfo;
// the previous node and its depth.
Node *prev_node = NULL;
int prev_depth = -1;

q.enqueue(make_pair(root,0));
while( !q.isempty())
{
NodeInfo ni = q.dequeue();
if (prev_node && (prev_depth == ni.second) )
{
/* previous node exists and the depth of the previous
* node is equal to the current node
* */
prev_node->next = ni.first;
}
else
{
ni.first->next = NULL;
}
prev_node = ni.first;
prev_depth = ni.second;

/* add the child nodes along with the depth */
q.enqueue( make_pair(ni.first->left, ni.second+1) );
q.enqueue( make_pair(ni.first->right, ni.second+1) );
}
}

Least Common Ancestor in a tree

Given two nodes of a tree, find the least common ancestor.

Case I : Each node has a pointer to its parent node.

Case II : A Binary Search Tree.

Case III : A Normal Binary Tree.

Example:

10
/ \
5 20
/ \ \
3 6 [21]
/ \
15 {30}
/ \ / \
13 {16} 25 35
\
17

Least common ancestor of 16, 30 is 21.



Solution:

Case I: Similar to finding the intersection of two linked lists. O(log(n)) complexity

Case II:

/**
* Find the least common ancestor in a Binary search tree,
* assuming n1->val < n2->val
* NOTE : In a BST there can be only one node between two given values.
* */
Node* FindLCA_BST(Node *root, Node *n1, Node *n2)
{
if ( !root )
return NULL;
if ( (root->val <= n2->val) && (root->val >= n1->val) )
return root;
else if (root->val < min)
{
/* goto right, a higher value */
return FindLCA_BST(root->right);
}
else
{
return FindLCA_BST(root->left);
}

}


Case III:

/** Find the Least common ancestor for any given binary tree
* and two nodes n1, and n2 and either n1 or n2 can be an ancestor
* of one another.
* */
bool FindLCA(Node *root, Node* n1, Node* n2, Node** lca)
{
if(!root)
return false;
else
{
// Is the current node one of the required nodes;
bool isCur = (n1 == root) || (n2 == root);
// check the left subtree
bool isLeft = FindLCA(root->left, n1, n2, lca);
// check the right subtree
bool isRight = FindLCA(root->right, n1, n2, lca);

if ( (isLeft && isRight) // both the nodes occur as the children of given node
|| (isCur && isLeft) // either of n1 or n2 is the ancestor of the other.
|| (isCur && isRight)
)
{
*lca = root;
return true;
}
else
return isLeft || isRight || isCur; // Let the parent decide the result.
}
}

Subset trees

Given a big tree and a small tree, give an algo to find if the small tree is a subset of the big tree.

Solution 1:


//Time Complexity : O(mn) , where is m and n are the number of nodes in the trees.
bool isSubtree(Node* bigTree, Node* smallTree)
{
if(!bigTree && !smallTree)
return true;
else if( (!bigTree && smallTree) ||
(bigTree && !smallTree)
)
return false;

if ( bigTree->node == smallTree->node )
{
/* If the node value matches, then check the left and right
* subtrees
* */
bool isLeftSubTree = isSubtree (bigTree->left, smallTree->left);
if (isLeftSubTree)
isRightSubTree = isSubtree (bigTree->right, smallTree->right);
if (isLeftSubTree && isRightSubTree )
return true;
}
/* we need to check in left subtree and right subtree */
isLeftSubTree = isSubtree(bigTree->left, smallTree);
if (isLeftSubTree )
return true;
else
return isSubtree(bigTree->right, smallTree);

}




Solution 2:

Use a suffix tree.
1. do a traversal { takes O(m) } for the larger tree and create a suffix tree.{ takes O(m) time + O(m) space }

2. do a traversal { takes O(n) } for the smaller tree and check if this pattern exists in the suffix tree. { O(n) time }

Sorted Array to Binary Tree

Given a sorted (non-decreasing order) array, write an algorithm to
create a binary tree with minimal height. Do this in O(n).

Answer:

The trick is to add the mid element of the array first, because if the elements are sequentially , then the tree will resemble a linked list.

Node* CreateTree(int* array, size_t begin, size_t end)
{
if( begin > end )
return NULL;
size_t mid = (begin+end) / 2;
Node* n = CreateNode(array[mid]);
n->left = CreateTree( array, begin, mid-1 );
n->right = CreateTree( array, mid+1, end );
return n;
}

Given the Infix and Postfix traversal, construct the tree

Given the Infix and Postfix traversal, construct the tree

Answer:
Possible only in cases where there are unique elements.


/**
* Program to construct a tree from a Infix and prefix traversals.
* */
#include
using namespace std;

struct TreeNode
{
char node;
TreeNode *left;
TreeNode *right;
TreeNode(char ch)
{
this->node = ch;
this->left = 0;
this->right = 0;
}
};
template
TreeNode* CtorTree(RandIter infix_begin, RandIter infix_end, RandIter postfix_begin, RandIter postfix_end)
{
/* Nothing to add */
if( (infix_begin == infix_end) || (postfix_begin == postfix_end) )
return NULL;
/* The current element in the postfix becomes the root */
TreeNode *tnode = new TreeNode(*postfix_begin);
/* Search for the root in infix representation from reverse */
RandIter j = infix_end;
while( j>= infix_begin )
{
--j;
if (*j == *postfix_begin)
break;
}
ptrdiff_t num_nodes = j - infix_begin;
++postfix_begin;

/* we have found the corresponding root at location j */
TreeNode *left_subtree = CtorTree(infix_begin, j, postfix_begin , postfix_begin + num_nodes);
TreeNode *right_subtree = CtorTree(j+1, infix_end, postfix_begin + num_nodes , postfix_end );
tnode->left = left_subtree;
tnode->right = right_subtree;
return tnode;
}

void Infix_traversal(TreeNode* n)
{
if (n)
{
Infix_traversal(n->left);
cout << n->node;
Infix_traversal(n->right);
}
}

int main(int argc, char ** argv)
{
if ( argc != 3 )
{
cerr << "Usage:" << argv[0] << " infix prefix " << endl;
}
else
{
char *infix = strdup(argv[1]);
char *prefix = strdup(argv[2]);
TreeNode *tree = CtorTree(infix, infix+strlen(infix), prefix, prefix + strlen(prefix));
cout << endl << "The Infix traversal of the constructed tree : " << endl;
Infix_traversal (tree);
free (infix);
free (prefix);
}
return 0;
}

Find longest run of a letter in a string

Write a function that returns the longest run of a letter in a string. e.g. cccc in the string abccccdef.

Answer:
O(n) solution which sweeps thru the array..



cur next
| |
accccefgggggg

GetRepSeq(const char* str, char **start, size_t *len)
{
const char* next = str + 1;
const char* cur = str;
size_t cur_len = 1;
*start = 0;
*len = 1;
while (*next)
{
if ( *next == *cur )
{
++next;
++cur_len;
}
else
{
/* we just encountered a non equal char */
if ( cur_len >= *len )
{
*len = cur_len;
*start = cur;
}
cur = next;
++next;
}
}
}




Alternative Answer : Sufix trees

Longest Panlindrome in a string

Write a function that returns the longest palindrome in a given string. e.g "ccddcc" in the string "abaccddccefe"

Answer (select to see):

Use Suffix trees (http://www.allisons.org/ll/AlgDS/Tree/Suffix/)

Longest common Substring

Given 2 input strings, find the longest string that occurs in both.

Answer (select to see):

Use Suffix trees (http://www.allisons.org/ll/AlgDS/Tree/Suffix/)