Google Interview Question
Software Engineer / DevelopersMaybe I don't understand completely your solution, but in the following case:
(3,7)(2,6)(5,5)(1,4)(4,3) partitioning values according step 2, in the first place the node (4,3) will be put in the right tree while it should be put in the left tree. Could you help me to understand your solution?
thank you
I think this algorithm is better than the one proposed by Vipul, since Vipul's algorithm is not guaranteed to produce a complete binary tree, which is one of the prerequisite for a binary tree to be a heap.
@above.. there are cases where you can never have a balanced tree which you want for heap .. consider this
(4,4) (3,3) (2,2) .. there is only one way tree can constructed and it will not be balanced.
Just have the same idea. post my code here:
int partitionBST(vector<int> &bstval, vector<int> &heapval, int s, int e)
{
int k = s;
for(int i=s+1; i<=e; i++)
{
if (heapval[i] > heapval[k])
{
k = i;
}
}
swap(heapval, k, e);
swap(bstval, k, e);
int i = s-1;
for(int j=s; j<e; j++)
{
if (bstval[j] <= bstval[e])
{
i++;
swap(bstval, i, j);
swap(heapval, i, j);
}
}
i++;
swap(bstval, i, e);
swap(heapval, i, e);
return i;
}
TreeNode2* buildBSTHeap(vector<int> &bstval, vector<int> &heapval, int s, int e)
{
if (s > e)
{
return NULL;
}
else if (s == e)
{
return new TreeNode2(bstval[s], bstval[e]);
}
int k = partitionBST(bstval, heapval, s, e);
TreeNode2* root = new TreeNode2(bstval[k], bstval[k]);
root->left = buildBSTHeap(bstval, heapval, s, k-1);
root->right = buildBSTHeap(bstval, heapval, k+1, e);
return root;
}
A treap is the correct way to implement this. Add the BST nodes one by one according to the usual rules. After each, consider the heap property of the new BST node and its parent. If the heap property is violated, perform tree rotations until the new node is the root or the heap property is satisfied.
Runtime is O(n*lg n), since each of the n BST insertions takes (lg n)
and no node must be rotated (lg n) times
The BST may be horribly unbalanced, but that wasn't a requirement, so there.
I think we can do it the following way:
Sort the nodes in decreasing order of their j values and then simply build the BST according to the i values starting from the first node in the obtained sorted list. The first node will be the root.
For example, let the given nodes (i,j pairs) be:
(12,6) (18,25) (19,10) (17,5) (19,10) i.e. 5 nodes
nodes after sorting in decreasing order according to j values:
(18,25) (16,11) (19,10) (12,6) (17,5)
So the tree would be something like this:
(18,25)
|
| |
(16,11) (19,10)
|
| |
(12,6) (17,5)
As we can see, the i values obey BST property and the j values obey MaxHeap property.
Tell me, what do u think?
Sorry for the previous messed up tree....
For example, let the given nodes (i,j pairs) be:
(12,6) (18,25) (19,10) (17,5) (19,10) i.e. 5 nodes
nodes after sorting in decreasing order according to j values:
(18,25) (16,11) (19,10) (12,6) (17,5)
So the tree would be something like this:
(18,25)
|
| |
(16,11) (19,10)
|
| |
(12,6) (17,5)
Here is my recursive solution:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int i;
int j;
struct node *left;
struct node *right;
};
void mySwap(struct node **n1, struct node **n2)
{
struct node *tmp;
tmp = *n1;
*n1 = *n2;
*n2 = tmp;
}
struct node *myInsert(struct node *root, struct node *nodeToInsert)
{
if(root == NULL)
{
return nodeToInsert;
}
else
{
if(nodeToInsert->i <= root->i)
{
root->left = myInsert(root->left,nodeToInsert);
}
else
{
root->right = myInsert(root->right,nodeToInsert);
}
return root;
}
}
void myFunc(struct node *arr[], struct node **resultTree, int size)
{
if(!size)
return;
int ind;
int maxInd = 0;
for(ind=0;ind<size ind++) //Finding the node with maximum j
if(arr[ind]->j > arr[maxInd]->j)
maxInd = ind;
*resultTree = myInsert(*resultTree,arr[maxInd]);//inserting node with maximum j value
mySwap(&arr[maxInd],&arr[size-1]);
myFunc(arr,resultTree,size-1);
}
int main()
{
int n;
struct node *arr[100];
scanf("%d",&n);
int ind;
int ival,jval;
struct node *result = NULL;
for(ind=0;ind<n;ind++)
{
arr[ind] = (struct node*)malloc(sizeof(struct node));
printf("Enter the i and j values for the %dth node.\n",ind);
scanf("%d%d",&ival,&jval);
arr[ind]->i = ival;
arr[ind]->j = jval;
arr[ind]->left = NULL;
arr[ind]->right = NULL;
}
myFunc(arr,&result,n);
//levelOrderTraversal(result);
//PreOrderTraversal(result);
for(ind=0;ind<n;ind++)
free(arr[ind]);
return 0;
}
Plz find bugs if any :)
1. Sort the node by the first value and keep it in array 1, coz the mid-order reversal of a binary search tree is a fully sorted array.
2. Sort the node by the second value and keep it in array 2.
So the process becomes to keep finding the node in array 1 which has the smallest value in array 2, the left-side of that node in array 1 is its left subtree and the right-side is the right subtree.
Recursive alogrithm in array 1 would be more complex in time because for each part it is necessary to find the node which has the smallest second value in the sub-part.
But if you recursively construct the tree via array 2 and take a note of parrent node, the time complexity should be O(nlogn + n) = O(nlogn) totally.
package org.nrec.probs;
import java.util.Comparator;
public class MNodeI implements Comparator<MNode>{
@Override
public int compare(MNode arg0, MNode arg1) {
if(arg0.i > arg1.i){
return 1;
}else if(arg0.i < arg1.i){
return -1;
}
return 0;
}
}
package org.nrec.probs;
import java.util.Comparator;
public class MNodeI implements Comparator<MNode>{
@Override
public int compare(MNode arg0, MNode arg1) {
if(arg0.i > arg1.i){
return 1;
}else if(arg0.i < arg1.i){
return -1;
}
return 0;
}
}
package org.nrec.probs;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.Stack;
public class MNode {
public MNode(int i ,int j){
this.i = i;
this.j = j;
}
public MNode(){
}
public MNode(MNode temp){
this.i = temp.i;
this.j = temp.j;
}
public String toString(){
return " i :: " + i + " j :: " + j;
}
public int i;
public int j;
MNode left;
MNode right;
public MNode createBSTHeap(List<MNode> numbers){
if(numbers == null || numbers.size() == 0){
return null;
}
Collections.sort(numbers,new MNodeJ());
MNode temp = numbers.get(0);
Collections.sort(numbers,new MNodeI());
int index = numbers.indexOf(temp);
System.out.println("index :: "+index);
System.out.println("temp :: "+temp);
System.out.println("Total :: "+numbers);
List<MNode> leftSubTree = null;
try{
leftSubTree = (List<MNode>) numbers.subList(0, index);
}catch(Exception e){
leftSubTree = null;
}
List<MNode> rightSubTree = null;
try{
rightSubTree = (List<MNode>) numbers.subList(index+1, numbers.size());
}catch(Exception e){
rightSubTree = null;
}
MNode root = new MNode(temp);
System.out.println("this node :: "+ root);
System.out.println("leftSubTree "+leftSubTree);
System.out.println("rightSubTree "+rightSubTree);
if(leftSubTree != null)
root.left = createBSTHeap(leftSubTree);
else root.left = null;
if(rightSubTree != null)
root.right = createBSTHeap(rightSubTree);
else
root.right = null;
System.out.println("Returning back \n node :: "+ root);
System.out.println("Left :: "+root.left);
System.out.println("Right :: "+root.right);
return root;
}
public void preorderI(MNode root){
if(root!=null){
preorderI(root.left);
System.out.print(root.i+",");
preorderI(root.right);
}
}
public void preorderJ(MNode root){
if(root!=null){
preorderJ(root.left);
System.out.print(root.j+",");
preorderJ(root.right);
}
}
public static void main(String[] args){
// (12,6) (18,25) (19,10) (17,5) (19,10)
MNode mnode1 = new MNode(12,6);
MNode mnode2 = new MNode(18,25);
MNode mnode3 = new MNode(19,10);
MNode mnode4 = new MNode(17,5);
MNode mnode5 = new MNode(19,10);
List<MNode> list = new ArrayList<MNode>();
list.add(mnode1);
list.add(mnode2);
list.add(mnode3);
list.add(mnode4);
list.add(mnode5);
MNode mnode = new MNode();
MNode root = mnode.createBSTHeap(list);
System.out.println(""+root.left);
System.out.println(""+root.right);
mnode.preorderI(root);
System.out.println("");
mnode.preorderJ(root);
}
}
Why not build the b-tree one node at a time. Find the height the new node should be at, then insert it toe the left or right as appropriate.
At any point in time, you are comparing 2 nodes. The one you want to place (P) and a Node in the tree (T). Each node has a search and heap value (P.i, P.j, T.i, T.j)
Recursively traverse down the tree, going left and right based on P.i vs T.i, until you find a T.j that is less than P.j. Now that you have the appropriate height, set T.parent = P (left or right, based on a comparison with parents.i) and, based on P.i vs T.i, set P.left or P.right = T.
Be sure to check the boundaries (No tree exists yet; T is the first node in the tree and P must be placed above it; P must become a leaf node on the left or right of T)
semi-pseudo code:
compareAndPlace (P, T, parent)
if !P // Bad placement parameter
throw
if !T // No tree exists
if parent // Parent must be null if T is null
throw
else // !parent, placement node is the new tree
return P
if P.j < T.j // P should be lower in the heap
if P.i < T.i // P should be left of T
if T.left // There is a left hand sub tree
compareAndPlace(P, T.left, T)
else // there is no left node for the present tree node
T.left = P
else // if P.i > T.i; P should be right of T
if T.right // There is a right subtree
compareAndPlace(P, T.right, T)
else // There is no right node for the present tree node
T.right = P
return T
else // P.j > T.j, T should be below P
if T.i < P.i // T should be to the left of P
P.left = T
else // T.i > P.i, T should be to the right of P
P.right = T
if parent
if P.i < parent.i // P should be to the left of parent
parent.left = P
else // P.i > parent.i, P should be to the right of parent
parent.right = P
return parent // * See note
else // No parent, we are at the top of the tree
return P
* The "return parent" line will only be reached if we have already traversed some distance down the tree. Thus, we are already in recursion and the returned result will be ignored.
My formatting was lost. Trying again:
compareAndPlace (P, T, parent)
{
if !P // Bad placement parameter
throw
if !T // No tree exists
{
if parent // Parent must be null if T is null
throw
else // !parent, placement node is the new tree
return P
}
if P.j < T.j // P should be lower in the heap
{
if P.i < T.i // P should be left of T
{
if T.left // There is a left hand sub tree
compareAndPlace(P, T.left, T)
else // there is no left node for the present tree node
T.left = P
}
else // if P.i > T.i, P should be right of T
{
if T.right // There is a right subtree
compareAndPlace(P, T.right, T)
else // There is no right node for the present tree node
T.right = P
}
return T
}
else // P.j > T.j, T should be below P
{
if T.i < P.i // T should be to the left of P
P.left = T
else // T.i > P.i, T should be to the right of P
P.right = T
if parent
{
if P.i < parent.i // P should be to the left of parent
parent.left = P
else // P.i > parent.i, P should be to the right of parent
parent.right = P
return parent // * See note
}
else // No parent, we are at the top of the tree
return P
}
}
Node * createTree(Node arr[], int low ,int high)
{
if(low > high) return;
else
{
index = findIndexOfMaxJValue(arr);
Node *root = malloc(arr[index]);
root->left = createTree( arr, low, index-1);
root->right = createTree( arr, index+1, high);
return root;
}
}
This Solution is similar to above one, but more easier to understand in recursion point of view:
- JuvN June 11, 20111. Find nodes with biggest j (we call it pivot) in node array.
2. Partition the array into two parts, all elements in left part have i smaller than i of pivot while all elements in right part have i bigger than i of pivot.
3. Use pivot as root of tree.
4. set left sub-tree of root as a tree built from left part of array.
5. set right sub-tree of root as a tree built from right part of array.
6. return root.
Average time complexity: O(NlogN)
Worst time complecity: O(N^2)