1
/ \
2 3
/ \ / \
4 5 6 7
for the given binary tree we need to create a matrix a[7][7]
satisfying the ancestor property like a[2][1]=1 since 1 is an ancestor of 2 ....
i solved it by using extra space an array ...the solution i came up is
int a[n][n]={0};
void updatematrix(int a[][n],struct node *root,int temp[],int index){
if(root == NULL)
return ;
int i;
for(i=0;i< index;i++)
a[root->data][temp[i]]=1;
temp[index]=root->data;
updatematrix(a,root->left,temp,index+1);
updatematrix(a,root->right,temp,index+1);
}
is there any mistake in my solution ?
can we do this inplace ???(i mean without using the temp array )
temp contains the path from root to current node, i.e. the set of nodes visited while walking down the tree to arrive at the current node.
If you have a parent pointer in each node (but I guess not), you can follow those pointers and walk up the tree to traverse the same set of nodes as temp. But this uses more memory.
You can also walk down the tree several times (pseudocode):
def updatematrix(a,node):
if node is null: return
walkDown(a.data,node.left)
walkDown(a.data,node.right)
updatematrix(a,node.left)
updatematrix(a,node.right)
def walkDown(data,node):
if node is null: return
a[node][data] = 1
walkDown(data,node.left)
walkDown(data,node.right)
Same complexity, but the pattern of memory access looks less cache friendly.
Related
Given an N-ary tree, I have to generate all the leaf to leaf paths in an n-array tree. The path should also denote the direction. As an example:
Tree:
1
/ \
2 6
/ \
3 4
/
5
Paths:
5 UP 3 UP 2 DOWN 4
4 UP 2 UP 1 DOWN 6
5 UP 3 UP 2 UP 1 DOWN 6
These paths can be in any order, but all paths need to be generated.
I kind of see the pattern:
looks like I have to do in order traversal and
need to save what I have seen so far.
However, can't really come up with an actual working algorithm.
Can anyone nudge me to the correct algorithm?
I am not looking for the actual implementation, just the pseudo code and the conceptual idea would be much appreciated.
The first thing I would do is to perform in-order traversal. As a result of this, we will accumulate all the leaves in the order from the leftmost to the rightmost nodes.(in you case this would be [5,4,6])
Along the way, I would certainly find the mapping between nodes and its parents so that we can perform dfs later. We can keep this mapping in HashMap(or its analogue). Apart from this, we will need to have the mapping between nodes and its priorities which we can compute from the result of the in-order traversal. In your example the in-order would be [5,3,2,4,1,6] and the list of priorities would be [0,1,2,3,4,5] respectively.
Here I assume that our node looks like(we may not have the mapping node -> parent a priori):
class TreeNode {
int val;
TreeNode[] nodes;
TreeNode(int x) {
val = x;
}
}
If we have n leaves, then we need to find n * (n - 1) / 2 paths. Obviously, if we have managed to find a path from leaf A to leaf B, then we can easily calculate the path from B to A. (by transforming UP -> DOWN and vice versa)
Then we start traversing over the array of leaves we computed earlier. For each leaf in the array we should be looking for paths to leaves which are situated to the right of the current one. (since we have already found the paths from the leftmost nodes to the current leaf)
To perform the dfs search, we should be going upwards and for each encountered node check whether we can go to its children. We should NOT go to a child whose priority is less than the priority of the current leaf. (doing so will lead us to the paths we already have) In addition to this, we should not visit nodes we have already visited along the way.
As we are performing dfs from some node, we can maintain a certain structure to keep the nodes(for instance, StringBuilder if you program in Java) we have come across so far. In our case, if we have reached leaf 4 from leaf 5, we accumulate the path = 5 UP 3 UP 2 DOWN 4. Since we have reached a leaf, we can discard the last visited node and proceed with dfs and the path = 5 UP 3 UP 2.
There might be a more advanced technique for solving this problem, but I think it is a good starting point. I hope this approach will help you out.
I didn't manage to create a solution without programming it out in Python. UNDER THE ASSUMPTION that I didn't overlook a corner case, my attempt goes like this:
In a depth-first search every node receives the down-paths, emits them (plus itself) if the node is a leaf or passes the down-paths to its children - the only thing to consider is that a leaf node is a starting point of a up-path, so these are input from the left to right children as well as returned to the parent node.
def print_leaf2leaf(root, path_down):
for st in path_down:
st.append(root)
if all([x is None for x in root.children]):
for st in path_down:
for n in st: print(n.d,end=" ")
print()
path_up = [[root]]
else:
path_up = []
for child in root.children:
path_up += child is not None and [st+[root] for st in print_root2root(child, path_down + path_up)] or []
for st in path_down:
st.pop()
return path_up
class node:
def __init__(self,d,*children):
self.d = d
self.children = children
## 1
## / \
## 2 6
## / \ /
## 3 4 7
## / / | \
## 5 8 9 10
five = node(5)
three = node(3,five)
four = node(4)
two = node(2,three,four)
eight = node(8)
nine = node(9)
ten = node(10)
seven = node(7,eight,nine,ten)
six = node(6,None,seven)
one = node(1,two,six)
print_leaf2leaf(one,[])
I have a tree. For example the following one:
root
a
/ \
b c
/ \ / \
e d f g
Every node in the tree has an attribute attr1. If a node's attr1 has a value of 1. Then the attr2 (another attribute) of all nodes on the path to this node, should make to 1. But we don't know if any of the nodes has a the value 1 in its attr1.
The idea I have to solve the problem is, to traverse through the tree (pre-order). While traversing I will have a FIFO container (queue) and every time I go downwards I will add to the queue and when going upwards I will remove the nodes which are bellow. So I have always the path to the current node. If then the node has attr1 == 1, then I must iterate the path again and set the attr2 of all nodes in the path to 2.
But I don't know if there is a more efficient way to accomplish this?
def update(node):
if node is None:
return False
upd_left = update(node.left)
upd_right = update(node.right)
node.attr2 = 1 if upd_left or upd_right or node.attr1 == 1 else node.attr2
return node.attr2 == 1
I think this will do what you expect as we are not iterating over the queue again and again.
The worst case complexity of your approach in case of a skewed tree will be O(n2). As for each node, you have to traverse the queue, if attr1==1 for each node.
But, in the above code, the complexity will be atmost O(n). Because you are visiting each node only once.
This is a question I got in an interview, and I'm still not fully sure how to solve it.
Let's say we have a tree of numbers, and we want to find the size of the largest connected region in the tree whose nodes have the same value. For example, in this tree
3
/ \
3 3
/ \ / \
1 2 3 4
The answer is 4, because you have a region of 4 connected 3s.
I would suggest a depth first search with a function that takes two inputs:
A target value
A start node
and returns two outputs:
the size of the subtree of node with values equal to the target value
the largest size of connected region within the subtree of node
You can then call this function with a dummy target value (e.g. -1) and the root node and it will return the answer in the second output.
In pseudocode:
dfs(target_value,start_node):
if start_node.value == target_value:
total = 1
best = 0
for each child of start_node:
x,m = dfs(target_value,child)
best = max(m,best)
total += x
return total,best
else
x,m = dfs(start_node.value,start_node)
return 0,max(x,m)
_,ans = dfs(-1, root_node)
print ans
Associate a counter with each node to represent the largest connected region rooted at that node where all the nodes are the same value. Initialize this counter to 1 for every node.
Run DFS on the tree.
When you back up from any node, if both nodes have the same value, add the child node's counter to the parent's counter.
When you're done, the largest counter associated with a node is your answer. You can keep track of this as you run the algorithm.
I have searched everywhere for this but there is only one method :
find predecessor (or successor) of node to delete
replace node with predecessor (or successor)
delete predecessor (or successor)
But i feel we can also do in this way :
pulloff the right(or left) element to the node to delete i.e just replace the
element to delete with right (or left) element and keep doing it till we encounter
the leaf and then delete the leaf.
In brief, keep replacing element to delete with its right(or left) element and keep doing it till we reach the leaf , and then delete the leaf.
So Is this method right ?
Unfortunately CoderAj, the solution provided by Vikhram is the correct way to delete a node in BST.
Your approach sounds good, but fails in the first replace itself.
Let's work out your approach on a tree.
8
5 25
3 7 23 30
6 24 27 35
Let us delete the root i.e. 8
Step 1:
25 //replaced 8 by 25
5 25
3 7 23 30
6 24 27 35
23 and 24 are less than 25, and still they lie in its right sub-tree.
Thus, your final tree would look like this
25
5 30
3 7 23 35
6 24 27
which does not look like a Binary Search tree.
I don't truly follow your algorithm (both of them). But below is how you delete a node from a Binary Tree (non-balancing).
Find the node to be deleted. This node can only be replaced by one of the 2 nodes in the existing tree
1. The leftmost (i.e. smallest) element of your right child node or
2. The rightmost (i.e. largest) element of your left child node.
Replace it with whichever is available and you are done
No other nodes need to be moved since
1. RightMostChildOfLeftChild() < CurrentNode() < LeftMostChildOfRightChild()
2. No nodes exist between RightMostChildOfLeftChild() and LeftMostChildOfRightChild() other than the CurrentNode()
Now if you don't mind just moving a bunch of nodes around, then there are lot of other ways to delete a node.
Hope that clarifies it for you.
For your subject question, the answer is yes; another method is possible.
There is a way that I discovered in a book of Sedgewick, which in my opinion is easier and general.
First, consider the exclusive join of two BST ts and tg'. Exclusive means that all the keys intsare smaller than any key intg`. So consider the following situation:
Now, if you select any root between ts or tg as the root of the exclusive join, you could recursively define the definitive result as follows:
In this case the root of the join is the root of ts.
Note that when you delete a complete node in a BST, its children are two exclusive trees in the sense previously defined. So you could define the deletion as follows:
Node * remove_from_bst(Node *& root, int key) noexcept
{
if (root == nullptr)
return nullptr; // In this case key was not found
// recursive searching of the key to be removed
if (key < root->key)
return remove_from_bst(root->left, key);
else if (root->key < key)
return remove_from_bst(root->right, key);
// here root contains a node with key
Node * ret_val = root; // backup of root that we will remove from tree
root = join_exclusive(root->left, root->right); // new subtree
return ret_val; // we return the removed node
}
Now, for finishing, we define the join_exclusive() operation:
Node * join_exclusive(Node *& ts, Node *& tg) noexcept
{
if (ts == nullptr)
return tg;
if (tg == nullptr)
return ts;
tg->left = join_exclusive(ts->right, tg->left);
ts->right = tg;
Node * ret_val = ts;
ts = tg = nullptr; // empty the trees
return ret_val;
}
This approach is for me easier because it manages the three cases: a leaf, an incomplete node and a complete node. In addition, the keys never are moved between nodes.
Since the root of the exclusive join is arbitrarily selected, this approach, as well as the yours, introduces a bias that tends to unbalance a random tree (the root selection was not randomly done). However, as Martinez & Roura propose for their random trees, you could store the cardinality of each subtree in the node. Then, you could perform a raffle that ponderates the cardinalities of each subtree. With this approach you could guarantee that the tree always is equivalent to a BST randomly built
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.