Construct binary tree from prefix order expression - binary-tree

How should we construct the binary tree of the following "prefix" order expression?
( - * / 8 + 5 1 4 + 3 - 5 / 18 6 )
Is there any rule to follow for drawing the tree?

Pseudocode is like this:
function MakeBinaryTree(expr):
element = next element in expr
if element is a number:
return a leaf node of that number
else: // element is an operator
left = MakeBinaryTree(expr)
right = MakeBinaryTree(expr)
return a binary tree with subtrees left and right and with operator element
Here expr keeps an internal pointer pointing to where the next element is.

Related

Algorithm to construct Fibonacci's tree with given minimum

I want to make a Fibonacci tree but with a minimum number other than 1, and I can't seem to find anything about it.
Here's an example of a "normal" fibonacci tree, with the minimum node 1.
5
/ \
3 7
/ \ /
2 4 6
/
1
What I want to do is for example, with minimum 3:
With height 0: it would be the empty tree.
With height 1:
3
With height 2:
4
/
3
With height 3:
5
/ \
4 6
/
3
With height 4:
7
/ \
5 9
/ \ /
4 6 8
/
3
...And so on.
My problem is, I can't seem to see a pattern in it, so I can't think of an algorithm to write.
I know that the left subtree's height is h-1 (where h is the original given height) and the right subtree's height is h-2. And I can't see how they calculate the root's number. But other than that, I'm really stuck.
Since the Fibonacci tree is a recursively defined structure, the easiest way is to think about a recursive algorithm.
This is some sort of C-style pseudo code (not covering any edge cases - I leave that to you as part of the exercise).
function createTree(height)
{
// basic cases
if(height == 0) return NULL;
if(height == 1)
{
node = new Node;
node.numNodesInTree = 1;
}
else
{
// according to the definition of the fibonacci tree
node = new Node;
node.leftChild = createTree(height - 1);
node.rightChild = createTree(height - 2);
node.numNodesInTree = node.leftChild.numNodesInTree
+ node.rightChild.numNodesInTree
+ 1; // also count the current node
}
return node;
}
You end up with a tree that has the Fibonacci structure, but not the right numbers yet. As a little helper, you have the number of nodes for each sub tree.
Then you can do something like:
function fillTree(offset, node, minimum) // offset means "all numbers in this subtree must be bigger than offset"
{
// According to the binary search tree definition,
// all numbers in the left sub tree have to be lower than
// the current node.
// All nodes in the right sub tree have to be larger.
node.value = node.leftChild.numNodesInTree // the number has to be bigger than all numbers in the left sub tree
+ 1 // (that's the "one bigger")
+ offset // offset for right subtrees
+ minimum - 1; // Just stupidly add the minimum (as mentioned in the comment to your question)
fillTree(offset, node.leftChild, minimum); // propagate offset to left children
fillTree(node.value, node.rightChild, minimum); // for the right sub tree, the current node's value is the new offset
// because all nodes in the right sub tree have to be bigger than the current node (binary search criterion)
}
Then you can call it like:
root = createTree(height);
fillTree(0, root, 3); // when initially calling it, the offset is always 0
// You can set the minimum arbitrarily (i.e. 3 as in your example)
Since this is pseudo code, I obviously haven't tested it, but you could get the idea behind that.

How find the longest consecutive path in a binary tree

I was asked in an interview this question. Consider a binary tree, we need to print the length of the longest path, where each element differs by 1.
EG:
6
/ \
5 7
/ \ / \
2 4 8 9
answer: 5
( 4,5,6,7,8 )
How to do this?
I developed an algoirthm to print increasing path from root to leaf, but I was not to develop one that keeps track of path that's on both subtrees.
EDIT: Need to get back the original tree after modification.
As suggested by #qwertyman in the comments
remove all invalid edges i.e edges whose difference is greater than 1
Now we have a forest, for each forest calculate the diameter as it is given in #Filip Kočica solution
The answer would be the max diameter out of all forests
For each subtree, you can calculate the longest increasing path down from the subtree root, the longest decreasing path down, and the longest internal path consisting of the increasing and decreasing paths down from the same node anywhere in the subtree.
It's easy to calculate these for a node if you already have them for all of its children, so you can do it as part of any postorder traversal.
The answer is the longest internal path within the whole tree.
Let longest_desc[a] be the longest 1-by-1 descending path going down from a
Similarly longest_asc[a], the longest 1-by-1 incremental path going down from a
For a fixed root R, the answer would be longest_desc[R] + longest_asc[R] - 1.
A brut force solution would do 2 dfs/bfs traversals from each node X to compute longest_asc[X] and longest_desc[X] and then merge them together. The resulting runtime complexity would be O(n^2).
But we can actually do better using dynamic programming:
longest_asc[X] = max(longest_asc[Y in children[X]] with Y = X + 1)
longest_desc[X] = max(longest_desc[Y in children[X]] with Y = X - 1)
Then we can compute all the values in a single DFS traversal => O(n) solution.
The answer is incorrect - another user correctly pointed out a bug. My solution below works only when the max length path passes through the root. In case, for example, the max length path is entirely in the left subtree and does not pass through the root, this answer fails. Feel free to read further to acquaint yourself with a recursive solution... and the bug in it.
I'm assuming that it is not important that the path has to have a difference of +1 as shown in your example. A difference of -1, resulting in a path like 4 -> 5 -> 4 -> 3 -> 4 -> 5 is ok as well.
public int getLongestConsecutivePath(TreeNode root) {
return root == null
? 0
: getLength(root.left, root.value) + getLength(root.right, root.value);
}
private int getLength(TreeNode node, int prevVal) {
return node == null || Math.abs(node.value - prevVal) > 1
? 0
: Math.max(getLength(node.left, node.value), getLength(node.right, node.value)) + 1;
}
Explanation:
If the root is not null, we get the max length in left and right subtree and sum it.
To get max length in a subtree, we recursively get the max length of right and left subtree of the subtree.
If we have reached the leaf OR if we have reached a node where the difference in value is greater than 1, we return 0.
Else we recursively get the max length from the left and right subtree and add 1 to it to accommodate for this node itself.

Algorithm to find the maximum non-adjacent sum in n-ary tree

Given an n-ary tree of integers, the task is to find the maximum sum of a subsequence with the constraint that no 2 numbers in the sequence should share a common edge in the tree.
Example:
1
/ \
2 5
/ \
3 4
Maximum non adjacent sum = 3 + 4 + 5 = 12
The following is the faulty extension of the algorithm outlined in http://www.geeksforgeeks.org/maximum-sum-such-that-no-two-elements-are-adjacent?
def max_sum(node, inc_sum, exc_sum):
for child in node.children:
exc_new = max(inc_sum, exc_sum)
inc_sum = exc_sum + child.val
exc_sum = exc_new
inc_sum, exc_sum = max(max_sum(child, inc_sum, exc_sum),
max_sum(child, inc_sum, inc_sum - node.val))
return exc_sum, inc_sum
But I wasn't sure if swapping exc_sum and inc_sum while returning is the right way to achieve the result and how do I keep track of the possible sums which can lead to a maximum sum, in this example, the maximum sum in the left subtree is (1+3+4) whereas the sum which leads to the final maximum is (3+4+5), so how should (3+4) be tracked? Should all the intermediary sums stored in a table?
Lets say dp[u][select] stores the answer: maximum sub sequence sum with no two nodes having edge such that we consider only the sub-tree rooted at node u ( such that u is selected or not ). Now you can write a recursive program where state of each recursion is (u,select) where u means root of the sub graph being considered and select means whether or not we select node u. So we get the following pseudo code
/* Initialize dp[][] to be -1 for all values (u,select) */
/* Select is 0 or 1 for false/true respectively */
int func(int node , int select )
{
if(dp[node][select] != -1)return dp[node][select];
int ans = 0,i;
// assuming value of node is same as node number
if(select)ans=node;
//edges[i] stores children of node i
for(i=0;i<edges[node].size();i++)
{
if(select)ans=ans+func(edges[node][i],1-select);
else ans=ans+max(func(edges[node][i],0),func(edges[node][i],1));
}
dp[node][select] = ans;
return ans;
}
// from main call, root is root of tree and answer is
// your final answer
answer = max(func(root,0),func(root,1));
We have used memoization in addition to recursion to reduce time complexity.Its O(V+E) in both space and time. You can see here a working version of
the code Code. Click on the fork on top right corner to run on test case
4 1
1 2
1 5
2 3
2 4
It gives output 12 as expected.
The input format is specified in comments in the code along with other clarifications. Its in C++ but there is not significant changes if you want it in python once you understand the code. Do post in comments if you have any doubts regarding the code.

Count number of unique node sequences producing the same BST

The problem:
Given a particular sequence of up to 50 integers, which represent
nodes of a certain binary search tree (BST), how many permutations of
this sequence are there, which will also give rise to exactly the same
BST? Include the original sequence in your total count as 1 sequence.
For instance, answer = 6 for such a sequence [5,2,1,9,8]: [5,2,1,9,8]
(itself, the original sequence given), [5,9,8,2,1], [5,2,9,1,8],
[5,9,2,1,8], [5,2,9,8,1], [5,9,2,8,1]
Suppose you have your example sequence [5,2,1,9,8]. The first node will become the root of the binary tree, so we know the first node must be 5.
From then on, all the nodes smaller than 5 will go to the left child, and all the nodes greater than 5 will go to the right child.
So you can solve this recursively, count the number of ways of making the left subtree (consisting of [2,1]) multiply by the number of ways of making the right subtree (consisting of [9,8]) and multiply by the number of ways of ordering the arrival of integers on opposite sides.
Sample code
def nCr(n,r):
"""Return number of ways of choosing r objects from n"""
top, bottom = 1, 1
for i in xrange(r):
top *= n
n = n - 1
bottom *= r
r = r- 1
return top / bottom
def count_ways_to_make_bst(seq):
if len(seq)<=1:
return 1
num_remaining = len(seq) - 1
left = [r for r in seq[1:] if r>seq[0]]
right = [r for r in seq[1:] if r<seq[0]]
return count_ways_to_make_bst(left) * count_ways_to_make_bst(right) * nCr(num_remaining,len(left))
Assume that the given node sequence is the order in which we added those elements into the BST.
We can easily see that if two nodes a and b belong to two different branches, so the order of adding a and b will not affect the final structure.
We only need to ensure that the parent need to be added first, before its children is added.
For the example [5,2,1,9,8]: 5 should always added first.
There will be only two choices: add 2 or add 9
If we add 2: 1 can be added in any order
similarly, If we add 9: 8 can be added anytime after that
So, now we have our algo while travelling from root -> leaf:
int numberOfWays (Node node) {
if(node is leaf) return 1;
int a = numberOfWays(node.left);
int b = numberOfWays(node.right);
int x = number of node in the left;
int y = number of node in the right;
//nCr is combination, so we can choose x places in total of x + y positions
return nCr(x+y,x) * a * b;
}

radix trie with rank/select operations

Now I am implementing a radix trie (also called patricia trie) to index sorted character strings.
So I need a rank() operation to know how many nodes are existed in left of the matched node.
More formally,
rankT(x) = |{t∈T | t < x}| for T⊆U and x∈U, where T is a radix trie and U is a universe of key.
meaning that calculation of the number of left leaf nodes in the trie.
For example, there are three keys such that
key set = {"abc", "def", "ghi"}, and index is 0, 1, 2.
So the patricia trie stores these like below:
root
/ | \
abc def ghi
and the rank() function should return 1 if key is "def", and 0 if key is "abc".
My question is that how can implement the rank() operation efficiently? I think a recalculation of rank of the node after each insertion is inefficient.
The exposition of radix trie is as below:
http://en.wikipedia.org/wiki/Radix_tree
Thanks~
To be able to insert words and calculate rank quickly, you could store a value representing the number of words in the subtree on each node. Then when querying the rank you could travel up from the leaf node x to the root accumulating the value for the rank(x)
So for example you could have a radix trie like (number in paren is number of words in subtree) of words "a", "bcd", "bg" and "def"
root
/ | \
a(1) | def(1)
b(2)
/ \
cd(1) g(1)
To find the rank() of word "bg". You start at node g(1) and you go up:
At node b(2) you you accumulate the values of all subtrees left of g(1). Set rank(bg) = size(cd)
At node root you you accumulate the values of all subtrees left of b(2). So
rank(bg) = size(cd) + size(a) = 1 + 1 = 2
To find the rank() of word "def"
At node root you you accumulate the values of all subtrees left of def(1). So
rank(def) = size(a) + size(b) = 2 + 1 = 3
As far as runtime is concerned: For string x you may go through trough len(x) parent nodes. And at each node there can be at most |A| children, where A is your alphabet. So the runtime would be O(len(x) * |A|)

Resources