Related
What exactly is the top view of a binary tree?
I find great ambiguity and lack of clarity from the articles I find.
For example, this is what is used to demonstrate the top view on geeksforgeeks:
1
/ \
2 3
/ \ / \
4 5 6 7
They go on to say that the top view is 4 2 1 3 7. The problem here is that they leave a lot of speculation on what isn't the top view. Consequently it becomes ambiguous to implement in code.
Stackoverflow examples so far are not any better. Hackerrank's example is even worse.
So I am hoping someone will tell me explicitly what the top view is because I have been trying to find out for 2 days. For instance, what is the top view of this tree:
1
\
14
/ \
3 15
/ \
2 7
/ \
4 13
/ \ /
5 6 10
/ \
8 11
\ \
9 12
And if I may be bold to ask, why is it important?
Now to understand the definition of top view,the best way is to know how to find the top view of a tree.
Finding the top view is a combination of two traversals namely-> Level Order Traversal and Vertical Traversal(There are other ways too but this one is the most basic).
To visualise this,start drawing vertical lines in the tree,in your second example 6 vertical lines would be drawn covering nodes, 1st -> 2,5 || 2nd -> 1,3,4 || 3rd -> 14,7,6,8 || 4th -> 15,13,10,9 || 5th -> 11 || 6th -> 12.
Now traverse the leaders of these vertical lines and this will give the top view of the tree 2->1->14->15->11->12.
Its like your're keeping your eye on the top of the tree and start drawing straight lines,the nodes which the straight lines cut first before touching any other nodes is the top view of the tree.
Like all other questions on hackerrank which helps in strengthening your base concept ,finding top view helps you understand the level order traversal and the vertical traversal concepts in detail.
To answer your question i will ask you to assume a rough sketch to actually understand what the question top view asks for. You might assume you are watching this tree with the root of the binary tree as the peak of a tree from a helicopter from above.
Assume the rank of the root to be 0. You need to traverse the tree in level order. If you go towards left decrease the current rank by 1 and when going right increase the current rank by 1. You will then be able to see that only unique values of every rank comes out as output.
The rank is actually the horizontal distance from the root node.
Like in the first example :
------- 1 (0) -------
/ \
2 (0-1=-1) 3 (0+1=1)
/ \ / \
4 (-1-1=-2) 5 (-1+1=0) 6 (1-1=0) 7 (1+1=2)
In brackets i have written down the ranks to which i was referring to.
So the final output if asked to write from left to right as asked in GeeksForGeeks, you can print the corresponding numbers of each unique ranks sorted according to the ranks.
And i guess it is clear now as to why 5 (rank=0) and 6(rank=0) are not in the final answer. Since when seen from the top of a tree these numbers will be shadowed by 1(rank=0).
map<int,int> mp;
void topView(Node * root) {
if(!root)
return;
mp.insert({0,root->data});
queue<pair<Node*,int>> q;
q.push({root,0});
while(!q.empty()){
Node *tmp=q.front().first;
int dis=q.front().second;
q.pop();
if(tmp->left){
q.push({tmp->left,dis-1});
if(mp.find(dis-1)==mp.end()){
mp.insert({dis-1,tmp->left->data});
}
}
if(tmp->right){
q.push({tmp->right,dis+1});
if(mp.find(dis+1)==mp.end()){
mp.insert({dis+1,tmp->right->data});
}
}
}
for(auto i : mp){
cout<<i.second<<" ";
}
}
The accepted solution to the above problem.
Link : Well explained! Refer for step by step explanation. https://stackoverflow.com/a/31388101/13962659
I don't know of a technical or mathematical definition for you, but it would appear from the links that the top view of the tree is as follows:
Imagine your tree laid out on the surface of a table. Look from the root end of the table down along the length of it. Supposing that the values of nodes are written on small wooden blocks, and the links between them are represented by wooden blocks high enough to obscure any nodes behind them, which nodes can you see when you lower your head to table height? In the first example, 5 and 6 are obscure, whereas 2, 3, 4 and 7 extend outwards to the left or right such that they are still visible.
However, as your second example illustrates, this is ambiguous as to whether or not the nodes 2, 5, 11, 12, 13 extend far enough outwards to be visible.
It seems like a poorly defined concept, which probably means it's not worth worrying about.
I noticed that nobody explains why you need to use level order traversal exactly and not simply any other kind of recursive traversals.
And here's the reason: a binary tree might have skewed left subtree by overlapping the right one beneath it or vice versa, take a look at the examples below.
A B
1 5
/ \ / \
4 2 4 7
\ \ / /
6 5 9 11
\ /
3 13
\ /
11 7
\ /
2 3
So if you traverse left nodes first you will have wrongly written right first w:node values in test case A and if you start traversing right nodes first then testcase B fails
Only traversing level by level guarantees that you store a correct top view values.
It works well and easy solution
import java.util.*;
import java.io.*;
class Node {
Node left;
Node right;
int data;
Node(int data) {
this.data = data;
left = null;
right = null;
}
}
class Solution {
/*
class Node
int data;
Node left;
Node right;
*/
class Nodegen
{
Node node;
int gen;
public Nodegen(Node node,int gen)
{
this.node=node;
this.gen=gen;
}
}
public static void topView(Node root) {
Map<Integer,Nodegen> topview=new TreeMap<>();
new Solution().printView(root,0,0,topview);
// System.out.print(topview.size());
for (Map.Entry<Integer, Nodegen> entry : topview.entrySet()) {
System.out.print(entry.getValue().node.data+" ");
}
}
public void printView(Node root,int align,int gen,Map<Integer,Nodegen> map) {
if(root==null)
{
return ;
}
if(map.get(align)==null)
{
map.put(align,new Nodegen(root,gen));
}else{
if(map.get(align).gen>gen)
{
map.put(align, new Nodegen(root,gen));
}
}
int temp=align+1;
int temp1=align-1;
int temp2=gen+1;
printView(root.left,temp1,temp2,map);
printView(root.right,temp,temp2,map);
}
public static Node insert(Node root, int data) {
if(root == null) {
return new Node(data);
} else {
Node cur;
if(data <= root.data) {
cur = insert(root.left, data);
root.left = cur;
} else {
cur = insert(root.right, data);
root.right = cur;
}
return root;
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int t = scan.nextInt();
Node root = null;
while(t-- > 0) {
int data = scan.nextInt();
root = insert(root, data);
}
scan.close();
topView(root);
}
}
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.
So I am not asking diagonal view of a tree, which fortunately I already know. I am asking if I view a tree from 45-degree angle only a few nodes should be visible. So there is a plane which at an angle of 45-degrees from the x-axis. so we need to print all the nodes which are visible from that plane.
For example:
1
/ \
2 3
/ \ / \
4 5 6 7
So if I look from that plane, I will only see nodes [4, 6, 7] as 5 and 6 overlaps each other. If I add another node at 6, now it will hide 7. How to do that? I searched on internet but couldn't find the answer.
Thanks!
I am giving you an abstract answer as the question is not language specific.
The problem with logging trees like this is the use of recursion.
By that I mean the traversal is going down nodes and up nodes.
What if you wrote a height helper which would return the depth of the current node.
For each depth level, you place the value in an array.
Then, write the values of the array.
Then you could grab the length of the last array and determine the amount of spaces each node needs.
Allow the arrays to hold empty values or else you will have to keep track of which nodes dont have children.
int total_depth = tree.getTotalHeight();
int arr[total_depth] = {};
for(int i = total_depth; i--;){
// there is a formula for the max number of nodes at a given depth of a binary tree
arr[i] = int arr[maximum_nodes_at_depth]
}
tree.inorderTraverse(function(node){
int depth = node.getHeightHelper();
// check if item is null
if( node!=nullptr && node.Item != NULL)
{
arr[depth].push(node.Item)
}
else
{
arr[depth].push(NULL)
}
})
So now you would have to calculate the size of your tree and then dynamically calculate how many spaces should prefix each node. The lower the depth the more prefixed spaces to center it.
I apologize but the pseudocode is a mix of javascript and c++ syntax.... which should never happen lol
1 5
/ \ |
2 3 --> 2
/ \ / \ / \
4 5 6 7 1 4
|
3
/ \
6 7
Let say you have a binary tree like the one on the left and try to convert it to the one on the right.
What it does is that it bumps 'any' single leaf node of the binary tree -- this case '5' -- which makes the leaf node a new root node. The original root node (and it's children) -- this case '1' and its children -- takes up the then leaf node space.
What's would be the general algorithm for this?
Thank you for help.
That depends pretty much on the structure supporting the binary tree (for example, if you store the parent of each node or not, and so on). Supposing you store the value of the node and the left and right descendants (the most basic information), the problem is reduced to "reverse" all the arcs from the current root down to the node that will become the new root. Something like this, I guess, in Java-style pseudo-code:
void rev(Node u, Node v) {
// make v point back to u
if (v.left == null) v.left = u;
else v.right = u;
// free edge from u to link up
if (u.left == v) u.left = null;
else u.right = null;
}
boolean reroot(Node root, Node parent, Node newRoot) { // assumes that newRoot is a leaf
if (root != null)
if (root == newRoot) {
rev(root, parent);
return true;
} else {
if (reroot(root.left, root) || reroot(root.right, root)) {
rev(root, parent);
return true;
}
}
}
return false;
}
Nevertheless, I didn't test the code above.
EDIT: the initial call would be reroot(currentRoot, null, newRoot);
My thoughts: starting from a node, we add its parent node and another unexplored branch to the new tree as the new branches, and then we recursively build the new tree by iterating back through the original tree till its root.
a python style pseudo-code would be like this:
NewTree=Node
NoLongerChildNode=NULL
while (Node!=root):
NewTree.attach(Node.anotherchild(NoLongerChildNode))
NewTree=NewTree.attach(Node.parent)
NoLongerChildNode=Node
Node=Node.parent
NewTree.attach(Node.anotherchild(NoLongerChildNode))
For a given binary tree, find the largest subtree which is also binary search tree?
Example:
Input:
10
/ \
50 150
/ \ / \
25 75 200 20
/ \ / \ / \ / \
15 35 65 30 120 135 155 250
Output:
50
/ \
25 75
/ \ /
15 35 65
This answer previously contained an O(n log n) algorithm based on link/cut trees. Here is a simpler O(n) solution.
The core is a procedure that accepts a node, the unique maximum BSST rooted at its left child, the unique maximum BSST rooted at its right child, and pointers to the left-most and right-most elements of these BSSTs. It destroys its inputs (avoidable with persistent data structures) and constructs the unique maximum BSST rooted at the given node, together with its minimum and maximum elements. All BSST nodes are annotated with the number of descendants. As before, this procedure is called repeatedly from a post-order traversal. To recover the sub-tree, remember the root of the largest BSST; reconstructing it requires only a simple traversal.
I'll treat the left BSST only; the right is symmetric. If the root of the left BSST is greater than the new root, then the entire sub-tree is removed, and the new root is now left-most. Otherwise, the old left-most node is still left-most. Starting from the right-most node of the left BSST and moving upward, find the first node that is less than or equal to the root. Its right child must be removed; note now that due to the BST property, no other nodes need to go! Proceed to the root of the left BSST, updating the counts to reflect the deletion.
The reason this is O(n) is that in spite of the loop, each edge in the original tree is in essence traversed only once.
EDIT: collectively, the paths traversed are the maximal straight-line paths in a BST, except for the left spine and the right spine. For example, on the input
H
/ \
/ \
/ \
/ \
/ \
/ \
/ \
D L
/ \ / \
/ \ / \
/ \ / \
B F J N
/ \ / \ / \ / \
A C E G I K M O
here are the recursive calls on which each edge is traversed:
H
/ \
/ \
/ \
/ \
/ \
/ \
/ \
D L
/ h h \
/ h h \
/ h h \
B F J N
/ d d h h l l \
A C E G I K M O
The previous algorithm (see revisions) was O(n^2) - we can generalize it to O(n log n) by noticing the facts that:
If b is the root of the largest BST and b.left.value < b.value, then b.left is also in the BST (same for b.right.value ≥ b.value)
If b is the root of the largest BST and a is also in the BST, then every node between a and b is in the BST.
So if c is between a and b, and c is not in the BST rooted by b, neither is a (due to (2.)). Using this fact, we can easily determine if a node is in the BST rooted by any given ancestor. We'll do this by passing a node into our function along with a list of its ancestors, and the associated min/maxValues that the current child-node would have to satisfy if indeed that ancestor were the root of the largest BST (we'll call this list ancestorList). We'll store the entire collection of potential-roots in overallRootsList
Let's define a structure called potentialRoot as follows:
Each potentialRoot contains the following values:
* node: The node we are considering for the root of the BST
* minValue and maxValue: the range another node must fall between to be part of the BST rooted by node (different for every node)
* subNodes: A list of the rest of the nodes in the largest BST rooted by node
The pseudo code looks like this (note that all lists mentioned are lists of potentialRoots):
FindLargestBST(node, ancestorList):
leftList, rightList = empty lists
for each potentialRoot in ancestorList:
if potentialRoot.minValue < node.Value ≤ potentialRoot.maxValue:
add node to potentialRoot.subNodes (due to (1.))
(note that the following copies contain references, not copies, of subNodes)
add copy of potentialRoot to leftList, setting maxValue = node.Value
add copy of potentialRoot to rightList, setting minValue = node.Value
add the potentialRoot (node, -∞, +∞) to leftList, rightList, and overallRootsList
FindLargestBST(node.left, leftList)
FindLargestBST(node.right, rightList)
At the end overallRootsList will be a list of n potentialRoots, each with a list of subNodes. The one with the largest subNodes list is your BST.
Since there are < treeHeight values in ancestorList, then (assuming the tree is balanced), the algorithm runs in O(n log n)
Interesting question!
My earlier attempt was moronically wrong!
Here is another attempt (hopefully correct this time).
I am assuming the tree is connected.
Suppose for each node n of the tree, you had a set of descendants of n, Sn with the property that
For each member x of Sn, the unique path from n to x is a Binary Search Tree (it is only a path, but you can still consider it a tree).
For every descendant y of x, such that the path from n to y is a BST, y is in Sn.
The set of nodes Sn, gives you the largest BST rooted at n.
We can construct Sn for each node by doing a depth first search on the tree, and passing in the path information (the path from root to the current node) and updating the sets of the nodes in the path by backtracking along the path.
When we visit a node, we walk up the path, and check if the BST property is satisfied for that segment of the path walked up so far. If so, we add the current node to the corresponding set of the node of the path we just walked to. We stop walking the path the moment the BST property is violated. Checking if the path segment we walked so far is a BST can be done in O(1) time, for a O(path_length) time total processing time, for each node.
At the end, each node will have its corresponding Sn populated. We can walk the tree now and pick the node with the largest value of Sn.
The time taken for this is the sum of depths of the nodes (in the worst case), and that is O(nlogn) in the average case (see Section 5.2.4 of http://www.toves.org/books/data/ch05-trees/index.html), but O(n^2) in the worst case.
Perhaps a cleverer way to update the sets will guarantee a reduction in the worst case time.
The pseudo-code could be something like:
static Tree void LargestBST(Tree t)
{
LargestBST(t, new List<Pair>());
// Walk the tree and return the largest subtree with max |S_n|.
}
static Tree LargestBST(Tree t, List<Pair> path)
{
if (t == null) return;
t.Set.Add(t.Value);
int value = t.Value;
int maxVal = value;
int minVal = value;
foreach (Pair p in path)
{
if (p.isRight)
{
if (minVal < p.node.Value)
{
break;
}
}
if (!p.isRight)
{
if (maxVal > p.node.Value)
{
break;
}
}
p.node.Set.Add(t.Value);
if (p.node.Value <= minVal)
{
minVal = p.node.Value;
}
if (p.node.Value >= maxVal)
{
maxVal = p.node.Value;
}
}
Pair pl = new Pair();
pl.node = t;
pl.isRight = false;
path.Insert(0, pl);
LargestBST(t.Left, path);
path.RemoveAt(0);
Pair pr = new Pair();
pr.node = t;
pr.isRight = true;
path.Insert(0, pr);
LargestBST(t.Right, path);
path.RemoveAt(0);
}
LARGEST BINARY SEARCH TREE IN A BINARY TREE:
There are two ways we can approach this problem,
i)Largest BST not induced (From a node, all its children need not satisfy the BST condition)
ii)Largest BST induced (From a node , all its children will satisfy the BST condition)
We will discuss about the largest BST(Not Induced) here. We will follow bottom up approach(Post order traversal) to solve this.
a)Reach the leaf node
b)A tree node(from the leaf) will return a TreeNodeHelper object which has the following fields in it.
public static class TreeNodeHelper {
TreeNode node;
int nodes;
Integer maxValue;
Integer minValue;
boolean isBST;
public TreeNodeHelper() {}
public TreeNodeHelper(TreeNode node, int nodes, Integer maxValue, Integer minValue, boolean isBST) {
this.node = node;
this.nodes = nodes;
this.maxValue = maxValue;
this.minValue = minValue;
this.isBST = isBST;
}
}
c)Initially from the leaf node, nodes=1,isBST=true,minValue=maxValue=node.data . And further, the nodes count will be increased if it satisfies the BST condition.
d)With the help of this, we will check the BST condition with current node. And we will repeat the same till root.
e)From each node two objects will be returned. one for last maximum BST and another one for current BST satisfying nodes. So from each node(above leaf) (2+2)=4 (2 for left subtree and 2 for right sub tree) objects will be compared and two will be returned.
f) The final maximum node object from root will be the largest BST
PROBLEM:
There is a problem in this approach. While following this approach, if a subtree is not satisfying the BST condition with the current node, we can't simply ignore the subtree(even it has less number of nodes). For example
55
\
75
/ \
27 89
/ \
26 95
/ \
23 105
/ \
20 110
From the leaf nodes(20,110) the objects will be tested with node(105), it satisfies the condition. But when it reaches node(95) the leaf node(20) does not satisfy the BST condition. Since this solution is for BST(Not induced) we should not ignore node(105) and node(110) which satisfies the condition. So from node(95) we have to backtrack again testing BST condition and catch those nodes(105, 110).
The complete code for this implementation is available in this link
https://github.com/dineshappavoo/Implementation/tree/master/LARGEST_BST_IN_BT_NOT_INDUCED_VER1.0
A binary search tree will give you a sorted result if you do a IN-ORDER Traversal. So, do an in-order traversal for the entire binary tree. The longest sorted sequence is your largest binary search sub tree.
Do a inorder traversal of elements (VISIT LEFT, VISIT ROOT, VISIT RIGHT)
While doing so, get the node data, compare whether the previous node data is lesser than the next data. If so, increment counter by 1. Store the start node.
When the comparison fails, store the end node and reset counter to 0
Store this information (counter,start,end) node in an array structure to later find which is having the maximum value and that will give you the longest binary search sub tree
GetLargestSortedBinarySubtree(thisNode, ref OverallBestTree)
if thisNode == null
Return null
LeftLargest = GetLargestSortedBinarySubtree(thisNode.LeftNode, ref OverallBestTree)
RightLargest = GetLargestSortedBinarySubtree(thisNode.RightNode, ref OverallBestTree)
if LeftLargest.Max < thisNode.Value & RightLargest.Min > thisNode.Value
currentBestTree = new BinaryTree(LeftLargest, thisNode.Value, RightLargest)
else if LeftLargest.Max < thisNode.Value
currentBestTree = new BinaryTree(LeftLargest, thisNode.Value, null)
else if RightLargest.Min > thisNode.Value
currentBestTree = new BinaryTree(null, thisNode.Value, RightLargest)
else
currentBestTree = new BinaryTree(null, thisNode.Value, null)
if (currentBestTree.Size > OverallBestTree.Size)
OverallBestTree = currentBestTree
return currentBestTree
As BlueRaja pointed out, this algorithm is not correct.
It should really be called GetLargestSortedBinarySubtreeThatCanBeRecursivelyConstructedFromMaximalSortedSubtrees.
root(Tree L A R) = A
MaxBST(NULL) = (true, 0, NULL)
MaxBST(Tree L A R as T) =
let
# Look at both children
(L_is_BST, L_size, L_sub) = MaxBST(L)
(R_is_BST, R_size, R_sub) = MaxBST(R)
in
# If they're both good, then this node might be good too
if L_is_BST and R_is_BST and (L == NULL or root(L) < A) and (R == NULL or A < root(R))
then (true, 1 + L_size + R_size, T)
else
# This node is no good, so give back the best our children had to offer
(false, max(L_size, R_size), if L_size > R_size then L_sub else R_sub)
Looks at each tree node exactly once, so runs in O(N).
Edit: Crud, this doesn't consider that it can leave out some parts of a subtree. When I read subtree, I assumed "the entire tree rooted at some node". I may come back to fix this later.