Related
basically i am required to come out with a pseudocode for this. What i currently have is
dictionary = {}
if node.left == none and node.right == none
visit(node)
dictionary[node] = 1
This is only the leaf nodes, how do i get the size for each node(parent and root)?
You can do a post-order traversal to find the size of each node.
The idea is to first handle both left and right trees. Then, after they are processed - you can use this data to process the current node.
This should look something like:
count = 0
if (node.left != none)
count += visit(node.left)
if (node.right != none)
count += visit(node.right)
// self is included.
count += 1
// update the node
node.size = count
return count
The dictionary for visited nodes is not needed since this is a tree, it guarantees to end.
As a side note - the size attribute of each node, is an important one. It basically upgrades your tree to a Order Statistics Tree
well the concept is that each node will know it's subtree size by first knowing the subtree size of all it's child which is maximum two child here as it is a binary tree, so once it knows subtree size of all child it can then add up all of them and atlast add 1 to it's
result and then the same thing will be done by it's parent also and so on upto root node. if we think about leaf node, it
has no child, so result subtree size will be only 1 in which it include itself.
one this idea is clear, it is easy to write code
that while traversing we will first know the subtree size of child nodes of current node then add 1 in it, in case of leaf node it will have subtree size of 1 only, below is the pseudocode of traverse funtion which finds the subtree size of each node and store them in dictionary sizeDictionary and a visited dictionary/array having larger scope has been used to keep track of visited nodes.
traverse(Tree curNode, dictionary subTreeSizeDictionary)
visited[curNode] = true
subtreeSizeDictionary[curNode] = 0
for child of curNode
if(notVisited[child])
traverse(child , sizeDictionary)
subtreeSizeDictionary[curNode] += subtreeSizeDictionary[child]
subtreeSizeDictionary[curNode] += 1;
here it is binary tree, but as you can see from pseudocode this concept can be used for any valid tree, the time complexity is O(n) as we visited each node only once.
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.
struct node {
int value;
struct node* left;
struct node* right;
int left_sum;
int right_sum;
}
In a binary tree, from a particular node, there is a simply recursive algorithm to sum up all its child values. Is there a way to save the values calculated in the intermediate steps and store them as left_sum and right_sum in child nodes?
Will it be easier to do this bottom up by adding a struct node* parent link to the node definition?
No, this is clearly an exercise in recursion. Think about what the sum means. It's zero plus the "sum of all values from the root down".
Interestingly enough, the "sum of all values from the root down" is the value of the root node plus the "sum of all values from its left node down" plus the "sum of all values from its right node down".
Hopefully, you can see where I'm going here.
The essence of recursion is to define an operation in terms of similar, simpler, operations with a terminating condition.
The terminating condition, in this case, is the leaf nodes of the tree or, to make the code simpler, beyond the leaf nodes.
Examine the following pseudo-code:
def sumAllNodes (node):
if node == NULL:
return 0
return node.value + sumAllNodes (node.left) + sumAllNodes (node.right)
fullSum = sumAllNodes (rootnode)
That's really all there is to it. With the following tree:
__A(9)__
/ \
B(3) C(2)
/ \ \
D(21) E(7) F(1)
Using the pseudo-code, the sum is the value of A (9) plus the sums of the left and right subtrees.
The left subtree of A is the value of B (3) plus the sums of its left and right subtrees.
The left subtree of B is the value of D (21) plus the sums of its left and right subtrees.
The left subtree of D is the value of NULL (0).
Later on, the right subtree of A is the value of C (2) plus the sums of its left and right subtrees, it's left subtree being empty, its right subtree being F (1).
Because you're doing this recursively, you don't explicitly ever walk your way up the tree. It's the fact that the recursive calls are returning with the summed values which gives that ability. In other words, it happens under the covers.
And the other part of your question is not really useful though, of course, there may be unstated requirements that I'm not taking into account, because they're, well, ... unstated :-)
Is there a way to save the values calculated in the intermediate steps and store them as left_sum and right_sum in child nodes?
You never actually re-use the sums for a given sub-tree. During a sum calculation, you would calculate the B-and-below subtree only once as part of adding it to A and the C-and-below subtree.
You could store those values so that B contained both the value and the two sums (left and right) - this would mean that every change to the tree would have to propagate itself up to the root as well but it's doable.
Now there are some situations where that may be useful. For example, if the tree itself changes very rarely but you want the sum very frequently, it makes sense performance wise to do it on update so that the cost is amortised across lots of reads.
I sometimes use this method with databases (which are mostly read far more often than written) but it's unusual to see it in "normal" binary trees.
Another possible optimisation: just maintain the sum as a separate variable in the tree object. Initialise it to zero then, whenever you add a node, add its value to the sum.
When you delete a node, subtract its value from the sum. That gives you your very fast O(1) "return sum" function without having to propagate upwards on update.
The downside is that you only have a sum for the tree as a whole but I'm having a hard time coming up with a valid use case for needing the sum of subtrees. If you have such a use case, then I'd go for something like:
def updateAllNodes (node):
if node == NULL:
return 0
node.leftSum = updateAllNodes (node.left)
node.rightSum = updateAllNodes (node.right)
return node.value + node.leftSum + node.rightSum
change the tree somehow (possibly many times)
fullSum = updateAllNodes (root)
In other words, just update the entire tree after each change (or batch the changes then update if you know there's quite a few changes happening). This will probably be a little simpler than trying to do it as part of the tree update itself.
You can even use a separate dirtyFlag which is set to true whenever the tree changes and set to false whenever you calculate and store the sum. Then use that in the sum calculation code to only do the recalc if it's dirty (in other words, a cache of the sums).
That way, code like:
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
will only incur a cost on the first invocation. The other four should be blindingly fast since the sum is cached.
What's the best way to create a balanced binary search tree from a sorted singly linked list?
How about creating nodes bottom-up?
This solution's time complexity is O(N). Detailed explanation in my blog post:
http://www.leetcode.com/2010/11/convert-sorted-list-to-balanced-binary.html
Two traversal of the linked list is all we need. First traversal to get the length of the list (which is then passed in as the parameter n into the function), then create nodes by the list's order.
BinaryTree* sortedListToBST(ListNode *& list, int start, int end) {
if (start > end) return NULL;
// same as (start+end)/2, avoids overflow
int mid = start + (end - start) / 2;
BinaryTree *leftChild = sortedListToBST(list, start, mid-1);
BinaryTree *parent = new BinaryTree(list->data);
parent->left = leftChild;
list = list->next;
parent->right = sortedListToBST(list, mid+1, end);
return parent;
}
BinaryTree* sortedListToBST(ListNode *head, int n) {
return sortedListToBST(head, 0, n-1);
}
You can't do better than linear time, since you have to at least read all the elements of the list, so you might as well copy the list into an array (linear time) and then construct the tree efficiently in the usual way, i.e. if you had the list [9,12,18,23,24,51,84], then you'd start by making 23 the root, with children 12 and 51, then 9 and 18 become children of 12, and 24 and 84 become children of 51. Overall, should be O(n) if you do it right.
The actual algorithm, for what it's worth, is "take the middle element of the list as the root, and recursively build BSTs for the sub-lists to the left and right of the middle element and attach them below the root".
Best isn't only about asynmptopic run time. The sorted linked list has all the information needed to create the binary tree directly, and I think this is probably what they are looking for
Note that the first and third entries become children of the second, then the fourth node has chidren of the second and sixth (which has children the fifth and seventh) and so on...
in psuedo code
read three elements, make a node from them, mark as level 1, push on stack
loop
read three elemeents and make a node of them
mark as level 1
push on stack
loop while top two enties on stack have same level (n)
make node of top two entries, mark as level n + 1, push on stack
while elements remain in list
(with a bit of adjustment for when there's less than three elements left or an unbalanced tree at any point)
EDIT:
At any point, there is a left node of height N on the stack. Next step is to read one element, then read and construct another node of height N on the stack. To construct a node of height N, make and push a node of height N -1 on the stack, then read an element, make another node of height N-1 on the stack -- which is a recursive call.
Actually, this means the algorithm (even as modified) won't produce a balanced tree. If there are 2N+1 nodes, it will produce a tree with 2N-1 values on the left, and 1 on the right.
So I think #sgolodetz's answer is better, unless I can think of a way of rebalancing the tree as it's built.
Trick question!
The best way is to use the STL, and advantage yourself of the fact that the sorted associative container ADT, of which set is an implementation, demands insertion of sorted ranges have amortized linear time. Any passable set of core data structures for any language should offer a similar guarantee. For a real answer, see the quite clever solutions others have provided.
What's that? I should offer something useful?
Hum...
How about this?
The smallest possible meaningful tree in a balanced binary tree is 3 nodes.
A parent, and two children. The very first instance of such a tree is the first three elements. Child-parent-Child. Let's now imagine this as a single node. Okay, well, we no longer have a tree. But we know that the shape we want is Child-parent-Child.
Done for a moment with our imaginings, we want to keep a pointer to the parent in that initial triumvirate. But it's singly linked!
We'll want to have four pointers, which I'll call A, B, C, and D. So, we move A to 1, set B equal to A and advance it one. Set C equal to B, and advance it two. The node under B already points to its right-child-to-be. We build our initial tree. We leave B at the parent of Tree one. C is sitting at the node that will have our two minimal trees as children. Set A equal to C, and advance it one. Set D equal to A, and advance it one. We can now build our next minimal tree. D points to the root of that tree, B points to the root of the other, and C points to the... the new root from which we will hang our two minimal trees.
How about some pictures?
[A][B][-][C]
With our image of a minimal tree as a node...
[B = Tree][C][A][D][-]
And then
[Tree A][C][Tree B]
Except we have a problem. The node two after D is our next root.
[B = Tree A][C][A][D][-][Roooooot?!]
It would be a lot easier on us if we could simply maintain a pointer to it instead of to it and C. Turns out, since we know it will point to C, we can go ahead and start constructing the node in the binary tree that will hold it, and as part of this we can enter C into it as a left-node. How can we do this elegantly?
Set the pointer of the Node under C to the node Under B.
It's cheating in every sense of the word, but by using this trick, we free up B.
Alternatively, you can be sane, and actually start building out the node structure. After all, you really can't reuse the nodes from the SLL, they're probably POD structs.
So now...
[TreeA]<-[C][A][D][-][B]
[TreeA]<-[C]->[TreeB][B]
And... Wait a sec. We can use this same trick to free up C, if we just let ourselves think of it as a single node instead of a tree. Because after all, it really is just a single node.
[TreeC]<-[B][A][D][-][C]
We can further generalize our tricks.
[TreeC]<-[B][TreeD]<-[C][-]<-[D][-][A]
[TreeC]<-[B][TreeD]<-[C]->[TreeE][A]
[TreeC]<-[B]->[TreeF][A]
[TreeG]<-[A][B][C][-][D]
[TreeG]<-[A][-]<-[C][-][D]
[TreeG]<-[A][TreeH]<-[D][B][C][-]
[TreeG]<-[A][TreeH]<-[D][-]<-[C][-][B]
[TreeG]<-[A][TreeJ]<-[B][-]<-[C][-][D]
[TreeG]<-[A][TreeJ]<-[B][TreeK]<-[D][-]<-[C][-]
[TreeG]<-[A][TreeJ]<-[B][TreeK]<-[D][-]<-[C][-]
We are missing a critical step!
[TreeG]<-[A]->([TreeJ]<-[B]->([TreeK]<-[D][-]<-[C][-]))
Becomes :
[TreeG]<-[A]->[TreeL->([TreeK]<-[D][-]<-[C][-])][B]
[TreeG]<-[A]->[TreeL->([TreeK]<-[D]->[TreeM])][B]
[TreeG]<-[A]->[TreeL->[TreeN]][B]
[TreeG]<-[A]->[TreeO][B]
[TreeP]<-[B]
Obviously, the algorithm can be cleaned up considerably, but I thought it would be interesting to demonstrate how one can optimize as you go by iteratively designing your algorithm. I think this kind of process is what a good employer should be looking for more than anything.
The trick, basically, is that each time we reach the next midpoint, which we know is a parent-to-be, we know that its left subtree is already finished. The other trick is that we are done with a node once it has two children and something pointing to it, even if all of the sub-trees aren't finished. Using this, we can get what I am pretty sure is a linear time solution, as each element is touched only 4 times at most. The problem is that this relies on being given a list that will form a truly balanced binary search tree. There are, in other words, some hidden constraints that may make this solution either much harder to apply, or impossible. For example, if you have an odd number of elements, or if there are a lot of non-unique values, this starts to produce a fairly silly tree.
Considerations:
Render the element unique.
Insert a dummy element at the end if the number of nodes is odd.
Sing longingly for a more naive implementation.
Use a deque to keep the roots of completed subtrees and the midpoints in, instead of mucking around with my second trick.
This is a python implementation:
def sll_to_bbst(sll, start, end):
"""Build a balanced binary search tree from sorted linked list.
This assumes that you have a class BinarySearchTree, with properties
'l_child' and 'r_child'.
Params:
sll: sorted linked list, any data structure with 'popleft()' method,
which removes and returns the leftmost element of the list. The
easiest thing to do is to use 'collections.deque' for the sorted
list.
start: int, start index, on initial call set to 0
end: int, on initial call should be set to len(sll)
Returns:
A balanced instance of BinarySearchTree
This is a python implementation of solution found here:
http://leetcode.com/2010/11/convert-sorted-list-to-balanced-binary.html
"""
if start >= end:
return None
middle = (start + end) // 2
l_child = sll_to_bbst(sll, start, middle)
root = BinarySearchTree(sll.popleft())
root.l_child = l_child
root.r_child = sll_to_bbst(sll, middle+1, end)
return root
Instead of the sorted linked list i was asked on a sorted array (doesn't matter though logically, but yes run-time varies) to create a BST of minimal height, following is the code i could get out:
typedef struct Node{
struct Node *left;
int info;
struct Node *right;
}Node_t;
Node_t* Bin(int low, int high) {
Node_t* node = NULL;
int mid = 0;
if(low <= high) {
mid = (low+high)/2;
node = CreateNode(a[mid]);
printf("DEBUG: creating node for %d\n", a[mid]);
if(node->left == NULL) {
node->left = Bin(low, mid-1);
}
if(node->right == NULL) {
node->right = Bin(mid+1, high);
}
return node;
}//if(low <=high)
else {
return NULL;
}
}//Bin(low,high)
Node_t* CreateNode(int info) {
Node_t* node = malloc(sizeof(Node_t));
memset(node, 0, sizeof(Node_t));
node->info = info;
node->left = NULL;
node->right = NULL;
return node;
}//CreateNode(info)
// call function for an array example: 6 7 8 9 10 11 12, it gets you desired
// result
Bin(0,6);
HTH Somebody..
This is the pseudo recursive algorithm that I will suggest.
createTree(treenode *root, linknode *start, linknode *end)
{
if(start == end or start = end->next)
{
return;
}
ptrsingle=start;
ptrdouble=start;
while(ptrdouble != end and ptrdouble->next !=end)
{
ptrsignle=ptrsingle->next;
ptrdouble=ptrdouble->next->next;
}
//ptrsignle will now be at the middle element.
treenode cur_node=Allocatememory;
cur_node->data = ptrsingle->data;
if(root = null)
{
root = cur_node;
}
else
{
if(cur_node->data (less than) root->data)
root->left=cur_node
else
root->right=cur_node
}
createTree(cur_node, start, ptrSingle);
createTree(cur_node, ptrSingle, End);
}
Root = null;
The inital call will be createtree(Root, list, null);
We are doing the recursive building of the tree, but without using the intermediate array.
To get to the middle element every time we are advancing two pointers, one by one element, other by two elements. By the time the second pointer is at the end, the first pointer will be at the middle.
The running time will be o(nlogn). The extra space will be o(logn). Not an efficient solution for a real situation where you can have R-B tree which guarantees nlogn insertion. But good enough for interview.
Similar to #Stuart Golodetz and #Jake Kurzer the important thing is that the list is already sorted.
In #Stuart's answer, the array he presented is the backing data structure for the BST. The find operation for example would just need to perform index array calculations to traverse the tree. Growing the array and removing elements would be the trickier part, so I'd prefer a vector or other constant time lookup data structure.
#Jake's answer also uses this fact but unfortunately requires you to traverse the list to find each time to do a get(index) operation. But requires no additional memory usage.
Unless it was specifically mentioned by the interviewer that they wanted an object structure representation of the tree, I would use #Stuart's answer.
In a question like this you'd be given extra points for discussing the tradeoffs and all the options that you have.
Hope the detailed explanation on this post helps:
http://preparefortechinterview.blogspot.com/2013/10/planting-trees_1.html
A slightly improved implementation from #1337c0d3r in my blog.
// create a balanced BST using #len elements starting from #head & move #head forward by #len
TreeNode *sortedListToBSTHelper(ListNode *&head, int len) {
if (0 == len) return NULL;
auto left = sortedListToBSTHelper(head, len / 2);
auto root = new TreeNode(head->val);
root->left = left;
head = head->next;
root->right = sortedListToBSTHelper(head, (len - 1) / 2);
return root;
}
TreeNode *sortedListToBST(ListNode *head) {
int n = length(head);
return sortedListToBSTHelper(head, n);
}
If you know how many nodes are in the linked list, you can do it like this:
// Gives path to subtree being built. If branch[N] is false, branch
// less from the node at depth N, if true branch greater.
bool branch[max depth];
// If rem[N] is true, then for the current subtree at depth N, it's
// greater subtree has one more node than it's less subtree.
bool rem[max depth];
// Depth of root node of current subtree.
unsigned depth = 0;
// Number of nodes in current subtree.
unsigned num_sub = Number of nodes in linked list;
// The algorithm relies on a stack of nodes whose less subtree has
// been built, but whose right subtree has not yet been built. The
// stack is implemented as linked list. The nodes are linked
// together by having the "greater" handle of a node set to the
// next node in the list. "less_parent" is the handle of the first
// node in the list.
Node *less_parent = nullptr;
// h is root of current subtree, child is one of its children.
Node *h, *child;
Node *p = head of the sorted linked list of nodes;
LOOP // loop unconditionally
LOOP WHILE (num_sub > 2)
// Subtract one for root of subtree.
num_sub = num_sub - 1;
rem[depth] = !!(num_sub & 1); // true if num_sub is an odd number
branch[depth] = false;
depth = depth + 1;
num_sub = num_sub / 2;
END LOOP
IF (num_sub == 2)
// Build a subtree with two nodes, slanting to greater.
// I arbitrarily chose to always have the extra node in the
// greater subtree when there is an odd number of nodes to
// split between the two subtrees.
h = p;
p = the node after p in the linked list;
child = p;
p = the node after p in the linked list;
make h and p into a two-element AVL tree;
ELSE // num_sub == 1
// Build a subtree with one node.
h = p;
p = the next node in the linked list;
make h into a leaf node;
END IF
LOOP WHILE (depth > 0)
depth = depth - 1;
IF (not branch[depth])
// We've completed a less subtree, exit while loop.
EXIT LOOP;
END IF
// We've completed a greater subtree, so attach it to
// its parent (that is less than it). We pop the parent
// off the stack of less parents.
child = h;
h = less_parent;
less_parent = h->greater_child;
h->greater_child = child;
num_sub = 2 * (num_sub - rem[depth]) + rem[depth] + 1;
IF (num_sub & (num_sub - 1))
// num_sub is not a power of 2
h->balance_factor = 0;
ELSE
// num_sub is a power of 2
h->balance_factor = 1;
END IF
END LOOP
IF (num_sub == number of node in original linked list)
// We've completed the full tree, exit outer unconditional loop
EXIT LOOP;
END IF
// The subtree we've completed is the less subtree of the
// next node in the sequence.
child = h;
h = p;
p = the next node in the linked list;
h->less_child = child;
// Put h onto the stack of less parents.
h->greater_child = less_parent;
less_parent = h;
// Proceed to creating greater than subtree of h.
branch[depth] = true;
num_sub = num_sub + rem[depth];
depth = depth + 1;
END LOOP
// h now points to the root of the completed AVL tree.
For an encoding of this in C++, see the build member function (currently at line 361) in https://github.com/wkaras/C-plus-plus-intrusive-container-templates/blob/master/avl_tree.h . It's actually more general, a template using any forward iterator rather than specifically a linked list.
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.