Tuesday, April 26, 2016

Yesterday we were discussing rebuilding a tree from post order and in order traversals.
Today we see if we can rebuild a tree from preorder and post order:
We make the following observations:
1) the roots are found top down by walking the post order list in the reverse manner or the preorder in the forward manner
2) the length of the left subtree for any root in preorder is given by the number of nodes between its position in the postorder and the start for the subtree of the parent.
3) the position of the start of the subtree of the parent is given by the start of the post order or the start of the sibling in the post order depending on whether it is the left or the right subtree
4) In general, we can rebuild the tree if we know the sizes of either left or right subtree consistently. We don't need both but if we do that's great.
5)  the length of the right subtree is the distance between the the position of the left sibling and the root in the post order.
6) The subtrees may be null and we just need to be mindful of the size but not need to check it upfront.
7) Since the items 2) and 5) indicate that we need to the postion of a sibling for at least the root of the whole tree to begin with, it is important to identify one of the siblings first.
8) if the element next to the root in pre is the same as the element previous to the same root in post, then one of the subtrees is null.
9) Since we cannot say which of the subtree is null from 8), this problem is not possible to solve.

Consider:
Pre: AB
Post BA
and
Pre: AC
Post: CA

                    A

             B            C

        D      E          F     G

H    I    J    K         L   M    N    O
Pre:   A  B  D  H  I  E  J  K  C  F  L  M  G  N  O
Post: H   I   D  J   K E B  L  M F N   O  G  C   A
In:    H   D   I  B   J  E K A  L  F M   C  N  G   O

Here too we see that unless the left subtree and the right subtree are listed once on both sides of the root, the solution becomes difficult. Therefore inorder traversal is needed.

#coding exercise
int GetSmallestNumberListed(string number, int n) // assume unique
{
if (String.IsNullorEmpty(number) || n <= 0) return null;
for (int I =0; I < numbers.Length; I++ )
{
     if (Char.IsDigit(numbers[I]) == false)
     {
          return -1;
     }
}    
string sorted = number.sort();
int returnLength = number.Length - n;
if (returnLength <= 0) return -1;
sorted = sorted.substring(0, returnLength);
String result = null;
for (int I = 0; I < numbers.Length; I++)
{
  var candidate = string.Empty;
  if (sorted.Contains(numbers[I]))
  {
      candidate += numbers[I];
      for (int j = I+1; j < numbers.Length; j++)
      {
          if (sorted.contains(numbers[j]))
          {
              if (candidate.Length >= returnLength) break;
              candidate += numbers[j];
          }
      }
      if (result == null)
      {
              result =  candidate;
      }
      if (candidate.Length == returnLength && String.CompareOrdinal(candidate, result) <= 0)
      {
              result = candidate;
      }
  }
}
return result;
}

#codingexercise
int GetMissingSerialNumber(List<int> num)
{
int sum_of_n = num.Count x (numCount + 1)/2;
return sum_of_n-num.sum();
}

The sorting would help narrow down the range with the missing numbers logarithmically if there were more than one.
int binarysearch(List<int> num, int target, int start, int end)
{
assert (start <= end);
int mid = (start + end)/2;
if (num[mid] == target) return mid;
if ( mid == start) return -1;
if (num[mid] < target)
       return binarysearch(num, target, mid + 1, end);
else
       return binarysearch(num, target, start, mid-1);
}


Monday, April 25, 2016

Yesterday we were discussing rebuilding a tree from post order and in order traversals.
We made the following observations:
1) the roots are found top down by walking the post order list in the reverse manner
2) the length of the right subtree for any root is given by the number of nodes between its position in the inorder and that of its parent.
3) the position of the left sibling in post order is at an offset equal to the length of the right subtree to the left of the root in post order. The position of the right sibling is immediately before the root.
4)  the length of the left subtree is the distance between the the position of the right sibling and the root in the in order.
6) The subtrees may be null and we just need to be mindful of the size but not need to check it upfront.

                    A

             B            C

        D      E          F     G

H    I    J    K         L   M    N    O
Post: H I D J K E B L  M F N O G C A
In:    H D I B J E K A  L  F M C N G O

Node Rebuild(List<Node> post, List<node> in) // All nodes in list initialized with left and right = null and set only with data
{
assert( post != null && in != null);
assert (posts.Count() == in.Count());

for(int i =  post.Count()-1; I >= 0; I--)
{
     Node root = post[i];
     int inIndex= Array.indexOf(in, post[i]);
     if ( I > 0 && I < post.Count())
     {
     Int parent = findParentIndex (Post, i); //parent occurs to the right of root in post with left,right set
     Int parentin = in.Count();// defaults to in.Count()
     if (parent < post.Count())
          parentin = Array.indexOf(in, post[parent]);
     Int righttreelen = parentIn-inIndex-1;
     if (i-righttreelen-1 > 0)
          Root.left = post [i-righttreelen-1];
     Int right = i-1;
     if (right > 0)
         Root.right = post [right];
}
return post[post.Count() - 1];
}

int findParentIndex(List<node>post, int current)
{
int target = post.Count();
for (int i = current+1; i< post.Count(); i++)
{
if ( post[i].left == post[current] ||
      post[i].right == post[current]){
     target  =  i;
     break;
     }
}
return target;
}

For performance gain, we also made the observation that the length of the right subtree need to be calculated only when we know that the right subtree is not null. We already know this if the index of the previous element (right sibling)  in post happens to have an inorder index less than that of the root.

Sunday, April 24, 2016

Today we look at another coding problem along the same lines as the one we have seen in the previous post and the one before.
This time we have

// Postorder   C D B F E A
// Inorder       C B D A E F
// Build tree

We use relative comparisons which has worked for us before. Let us take the example of  our elemental subtree of a root with two siblings.
   J
K  L

1) All three nodes
    Post: K L J
    InOrder: K J L
2) Only left -subtree
    Post: K J
    In: K J    // L is missing because the previous element in post order lies within inIndex < that of J
3) Only right-subtree
    Post: L J
     InL J L  // K is missing when no elements appear before J whose inIndex < that of J
4) only root
Post:     Prev root Next
In :        Prev some-others root yet-others Next
4) is not differentiable from 2)

In general, with arbitrary sub-trees  for siblings
// left-subtree missing when
Previous node in pre appears to the rightof inIndex of root in inorder
// right-subtree missing when
previous element is left subtree in post order.

the sizes of the left and right sub tree can be kept track of because we use the same predecessor technique

                    A

             B            C

        D      E          F     G

H    I    J    K         L   M    N    O
Post: H I D J K E B L  M F N O G C A
In:    H D I B J E K A  L  F M C N G O

Node Rebuild(List<Node> post, List<node> in) // All nodes in list initialized with left and right = null and set only with data
{
assert( post != null && in != null);
assert (posts.Count() == in.Count());

for(int i =  post.Count()-1; I >= 0; I--)
{
Node root = post[i];
int inIndex= Array.indexOf(in, post[i]);
if ( I > 0 && I < post.Count())
{
//todo
int inIndexPrev = Array.indexOf(in, post[I-1]);
// Ignore comments below
// Ignore : Instead of taking subtree lengths, can we detect if subtrees are null from pattern
//Ignore: int inIndexNext = Array.indexOf(in, post[I+1]);
//Ignore: if both left and right subtree is null, handle it separately,
// Ignore: if (in.Count() - 1 - inIndex > 0)
// Ignore:if (inIndexPrev < inIndex && inIndexNext > inIndex)  continue;
//otherwise keep track of right subtree length as the differences in inorder indexes

     Int parent = findParentIndex (Post, i); //parent occurs to the right of root in post with left,right set
     Int parentin = Array.indexOf(in, post[parent]); // defaults to in.Count()
     Int righttreelen = parentIn-inIndex-1;
     if (i-righttreelen-1 > 0)
          Root.left = post [i-righttreelen-1];
     Int right = i-1;
     if (right > 0)
         Root.right = post [right];

}
return post[post.Count() - 1];
}


The recursive solution online is as follows:
public TreeNode buildTree(int[] inorder, int inStart, int inEnd,
int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd || postStart > postEnd)
return null;

int rootValue = postorder[postEnd];
TreeNode root = new TreeNode(rootValue);

int k = 0;
for (int i = 0; i < inorder.length; i++) {
if (inorder[i] == rootValue) {
k = i;
break;
}
}

root.left = buildTree(inorder, inStart, k - 1, postorder, postStart,
postStart + k - (inStart + 1));
// Becuase k is not the length, it it need to -(inStart+1) to get the length
root.right = buildTree(inorder, k + 1, inEnd, postorder, postStart + k- inStart, postEnd - 1);
// postStart+k-inStart = postStart+k-(inStart+1) +1

return root;
}



Saturday, April 23, 2016

Today we improve the performance of the previous code sample shown to reconstruct the tree from the preorder and inorder traversals.
The key to improving performance is that we do that many steps as it takes to rebuild the tree and as cheaply as possible. while this might sound cliched, it may translate to our problem this way. Are there any redundant operations in the previous code shown ? The answer is yes, We do repeated Array.IndexOf ? How do we avoid this?
Because we deal with a tree, we know all test cases can be covered by the elementary tree with a single node and two siblings where one or more nodes can be null.
Consequently, we take node J as root with left K and Right L
we have

1) Both siblings:
Pre: JKL
In: KJL
2) Right sibling only:
Pre: JL
In: JL
3) Left Sibling only
Pre: JK
In: KJ

When the siblings are trees
4) No leftchild:
Pre: J some-other-node
In: J  intermediary-nodes some-other-node
5) No right child:
Pre:  J some-other-node
In: some-other-node  intermediary-nodes J


Therefore we can use relative positions and indexes instead of absolute indexes to optimize the solution. We make the following observations:
The next element to a node in preorder has an index lesser than its own in the in order and this implies the next element is a left child.
The next element to a node has an immediate next index in the inorder as well then the next element is a right child
The next element to a node has an index greater than its own + 1, then it has no right child.
The previous element to a node in pre order occurs as the next element in the in order means that the node has no left child

Node Rebuild(List<Node> pre, List<node> in) // All nodes in list initialized with left and right = NULL and set only with data
{
assert( pre != NULL && in != null);
assert (pre.Count() == in.Count());

for(int i = 0; i < pre.Length; i++)
{
Node root = pre[i];
int inIndex= Array.indexOf(in, pre[i]);
if (i+1 < pre.Length && inIndex+1<in.Length)
{
//todo:
//set root.left
bool left = true;
for (int j =inIndex; j< in.Count(); j++)
     if (in[j] == pre[i+1])
       left = false;
if(left != false)
  root.left = pre[i+1];
//set root.right
bool right= true;
for (int j =inIndex; j>= 0 j--)
     if (in[j] == pre[i+1])
       right = false;
if(right != false){
   Node target = in[inIndex-1];
   for(int j =i+1; j<pre.Count();j++)
    if (pre[j] == target)
        root.right = pre[j];
}
}
}

return pre[0];
}

Some can claim that yesterday's approach was development oriented and today's approach is test-oriented and there may be some truth in that there are entrenched mindsets along those lines but the reality is that today's approach is leaned on for real world data.

Friday, April 22, 2016

Today we look at using the Binary tree traversals to reconstruct the tree. We mentioned in yesterday's post that the preorder traversal and the inorder traversal can be used to determine the length of the left and right subtree of any node at the same time. Let us take a look at the solution now.

// Preorder A B C D E F
// Inorder   C B D A E F
// Build tree

Node BuildTree(char[] Preorder, char[] InOrder, int index = 0)
{
 Node root = new Node();
 root.data = PreOrder[index];
 root.left = null;
 root.right = null;

 int inIndex = Array,indexOf(InOrder, Preorder[index]);

 if ( index+1 < Preorder.Length &&
       IsLeftSubtree(Preorder[index+1], inOrder, inIndex) == true)
       root.left = BuildTree(Preorder, InOrder, index + 1);

 if ( inIndex+1 < InOrder.Length &&
       isPredecessor(InOrder[inIndex+1], Preorder, index) == false)
       root.right = BuildTree(Preorder, InOrder, Array.IndexOf(PreOrder, InOrder[inIndex + 1]));

 return root;
}

bool is Predecessor(char c, char[] Preorder, int index)
{
return Array.IndexOf(Preorder, c) < index;
}

bool isLeftSubtree(char c, char[] inOrder, int index)
{
Array.IndexOf(Inorder,c) < index;
}

or iteratively as follows:


Node  BuildTree(List<Node> pre, List<Node> in) // Node.left = null; Node.right = null;
{
for (int i = 0; i < pre.Length; i++)
{
int index = i;
int inIndex = Array,indexOf(in, pre[index]);
if ( index + 1 < pre.Length &&
     Array.IndexOf(in, pre[index+1]) < index)
   pre[i].left = pre[index+1];
if (inIndex+1 < in.Length &&
    Array.IndexOf(pre, in[inIndex+1]) >= index)
    pre[i].right = Array.IndexOf(pre, in[inIndex+1]);
}
return pre[0];
}

Thursday, April 21, 2016

Today we look at a few more coding problems. Yesterday we said the traversal orders can be used to serialize the tree. If we are given a preorder traveral of a tree, can we verify that the tree is serialized without reconstructing? This means it can be linear in time complexity.
Let us take an example:
    9
 3    2
4 1 # 6
is serialized as 9,3,4,#,#,1,#,#,2,#,6,#,#

Note that we can remove the right most vertices if it has two null leaves and substitute it with null.
If this is mot the case then the parent has a left subtree and we start to do the same with the left sub tree until finally there is only one node remaining and it is null.

bool IsValidBT(List<Node> nodes)
{
bool isValid = false;
  int i = Nodes.Count-1;
  while (i >= 3)
  {
      if (Nodes[i] == null  && Nodes[i-1] == null  && Nodes[i-2] != null){
         nodes.RemoveRange(i-2, 3);
         nodes.Insert(i-2, null);
        i = i - 3;
        continue;
      }
      if(Nodes[i] != null){
          if (Nodes[i+1] == null  && Nodes[i+2] == null){
           nodes.RemoveRange(i, 3);
           nodes.Insert(i, null);
          }
          i=i-1;
        continue;
      }
     i = i -1;
  }
  if (i ==0 && nodes[i] == null) isValid = true;
  return isValid;
}

If we have a binary search tree and we have an inorder and preorder traversals,
then the two traversals can be used to simultaneously find the left and right subtree length of each node.

Wednesday, April 20, 2016

Today we continue more coding puzzles reviews. One of the problems is about serializing and deserializing a binary tree.
There are many ways to do it. Usually two different orders of traversal of a binary tree can give all the information to deserialize the binary tree. They are also efficient because each node is visited once during a traversal. Another way to do this would be to print the tree level wise with null nodes for missing child nodes of the tree. The level wise ensures one serialization result.
void serialize(Node root, Node delimiter, Node Empty)
{
var q = new Queue<Node>();
q.Enqueue(root);
q.Enqueue(delimiter);

var node = q.Dequeue();
while (node)
{
if (root.left)
      q.Enqueue(root.left) ;
else
      q.Enqueue(Empty); // new node

if (root.right)
      q.Enqueue(root.right);
else
      q.Enqueue(Empty); // new node

node = q.Dequeue();

Console.Write(node.toString());

if (node == delimiter) {q.Enqueue(delimiter);}

}
}

The deserialization now will find all the left or child nodes for every parent nodes even if they are null.

void deserialize(List<Node> nodes, Node delimiter)
{
int level = nodes.Index(nodes.First(x => x == delimiter));
level++;
for (int I = 0; I < nodes.Count() && level < nodes.Count(); I++)
{
   if (nodes[I] != delimiter)
   { nodes[I].left = nodes[level]; level++;
      nodes[I].right = nodes[level]; level++;
   }
   else
        assert nodes[level] ==delimiter
        level++;
}
}

Let's take an example:
   1
2   3
    4  5
1D23DEE45