Correct Answer: B
Last element in post order is the root of tree- find this element in inorder- $\log n$ time.
Now as in quick sort consider this as pivot and split the post order array into 2- possible because all elements smaller than pivot goes to left and all elements larger than pivot goes to right and suppose we have x elements smaller than pivot, these elements will be same in both inorder as well as postorder (order may change). We already got the root, now left child is the left split and right child is the right split.
So, doing this recursively gives time complexity of this approach as
$$T(n) = T(k) + T(n-k-1) + \log n$$
Solving would give $T(n) = O(n \log n)$ in worst case, by putting $k=0$ and shown at bottom.
But searching for an element in the inorder traversal of given BST can be done in $O(1)$ because we have $n$ elements from $1..n$ so there is no need to search for an element- if last element in post order is say $5$ we take it as root and since $4$ elements $(1..4)$ are smaller we split the post order array in to two- (first $4$ elements), ($6$th element onward) and solve recursively. Time complexity for this would be
$$T(n) = T(k) + T(n-k-1) + O(1)$$
which gives $T(n) = O(n).$
Since we know that all elements must be traversed at least once, $T(n) = \Omega(n)$ also and so $$T(n) = \Theta(n).$$ The following code is doing this.
//Install graphviz (sudo apt-get install graphviz on Ubuntu) to view output tree
#include<stdio.h>
#include<stdlib.h>
struct tree
{
struct tree* left;
struct tree* right;
int x;
};
struct tree* makenode(int x)
{
struct tree * root = malloc(sizeof(struct tree));
root -> x = x;
root -> left = root -> right = NULL;
return root;
}
struct tree* makeBST(int *post, int start, int n, int inorder){
if(n <= 0)
return NULL;
int pivot = post[start + n -1];
struct tree * root = makenode(pivot);
root -> left = makeBST(post, start, pivot-1 - inorder, inorder );
root -> right = makeBST(post, pivot - inorder - 1, n - (pivot - inorder), pivot);
return root;
}
void preorder(struct tree* node)
{
if(node == NULL)
return;
printf("%d ", node->x);
preorder(node->left);
preorder(node->right);
}
void printdot(struct tree* node, FILE * f)
{
if(node == NULL)
return;
if(node-> left != NULL)
{
fprintf(f, "%d -- %d;\n", node->x, node->left->x);
}
if(node-> right != NULL)
{
fprintf(f, "%d -- %d;\n", node->x, node->right->x);
}
printdot(node->left, f);
printdot(node->right, f);
}
int main(){
int i, n, *a;
printf("Enter n: ");
scanf("%d", &n);
a = malloc(n * sizeof(int));
printf ("Enter post order traversal: ");
for(i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
struct tree * tree = makeBST(a, 0, n, 0);
printf("Pre order traversal is : ");
preorder(tree);
printf("\n");
FILE * f = fopen("tree.dot", "w");
fprintf(f, "graph tree { \n");
printdot(tree, f);
fprintf(f, "}\n");
fclose(f);
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__) || (defined (__gnu_linux__)) )
system("dot -Tpng tree.dot -o output.png; eog output.png");
#endif
}
$$T(n) = T(k) + T(n-k-1) + \log n$$
Solving would give $T(n) = O(n \log n)$, by putting $k=0$,
$T(n) = T(0) +T(n-1) + \log n, \\\implies T(n) = O(1)+ \log n + \log (n-1) + \log (n-2) + \dots + \log 1\\\implies T(n) = n + \log n! \\\implies T(n) = O(n \log n).$
(Stirling's Approximation)
PS: Even for a general BST, given a post order traversal, we can construct the BST in $O(n)$ more stricter than $O(n \log n)$ derived above and this matches $\Omega(n)$ and hence we do have an $\Theta(n)$ algorithm. This algorithm can be seen at below link
https://www.geeksforgeeks.org/construct-a-binary-search-tree-from-given-postorder/