This question was asked in one of the interview : Given two unsorted array, check if it will create the same bst. eg: 2, 1, 4, 0 and 2, 1, 0, 4 will both form same BST.
2
/ \
1 4
/
0
please suggest some good algo.
This question was asked in one of the interview : Given two unsorted array, check if it will create the same bst. eg: 2, 1, 4, 0 and 2, 1, 0, 4 will both form same BST.
2
/ \
1 4
/
0
please suggest some good algo.
All the elements which are greater then the root element should appear in the same order in both the arrays
And of course the very first condition is that both the arrays should contain the same elements but in different order .
Hence this can be solved in linear time.
Pseudocode would be like this:
int GetNextIncresingElement(int[] arr, ref int index, int root)
{
for(int i = index; i< arr.Length; i++)
{
if(arr[i] > root)
{
index = i;
return arr[i];
}
}
return -1;
}
int GetNextDecreasingElement(int[] arr, ref int index, int root)
{
for(int i = index; i< arr.Length; i++)
{
if(arr[i] <= root)
{
index = i;
return arr[i];
}
}
return -1;
}
bool CheckFormsSameBST(int[] arr1, int[] arr2)
{
int index1 = 1;
int index2 = 1;
int num1;
int num2;
int root = arr1[0];
if(root != arr2[0])
return false;
while(true)
{
num1 = GetNextIncresingElement(arr1, ref index1, root);
num2 = GetNextIncresingElement(arr2, ref index2, root);
if(num1 != num2)
return false;
else
{
if(num1 == -1)
break;
}
index1++;
index2++;
}
index1 = 1;
index2 = 1;
while(true)
{
num1 = GetNextDecreasingElement(arr1, ref index1, root);
num2 = GetNextDecreasingElement(arr2, ref index2, root);
if(num1 != num2)
return false;
else
{
if(num1 == -1)
break;
}
index1++;
index2++;
}
return true;
}
I agree with the idea Peter and Algorist described. But I believe the sub-trees of each node (represented by the array less than this node and the array larger than it) need to be examined in this fashion as well. For example, 621407 and 621047 yield the same BST but 624017 does not. The function can be written recursively.
sample code added:
bool sameBST(int * t1, int * t2, int startPos, int endPos) {
int rootPos1, rootPos2;
if (endPos-startPos<0) return true;
if (t1[startPos]!=t2[startPos]) return false;
rootPos1=partition(t1,startPos,endPos,t1[startPos]);
rootPos2=partition(t2,startPos,endPos,t2[startPos]);
if (rootPos1!=rootPos2) return false;
return sameBST(t1,t2,startPos,rootPos1-1) && sameBST(t1,t2,rootPos1+1,endPos);
}
Function partition is the same one you use in quicksort. Apparently, T(n)=2T(n/2)+O(n), which leads to time complexity T(n)=O(nlogn). Because of the recursion, the space complexity is O(logn)
1)Sort the array using counting or radix sort.
2)Build tree using our sorted array and given unsorted array(for checking insertion order). It will preserve the structure of the tree.
3)Compare both trees.
All can be done in linear time - O(n).
Code:
import java.util.Arrays;
public class BSTFromUnsorted {
static class Node{
int key;
int arrivalTime,min,max,root;
Node left;
Node right;
Node(int k,int at){
key=k;left=null;right=null;arrivalTime=at;
}
}
public static void printTree(Node n){
if(n==null) return;
System.out.println(n.key+" "+ ((n.left!=null)?n.left.key:"-") + " " + ((n.right!=null)?n.right.key:"-") );
printTree(n.left);
printTree(n.right);
}
public static boolean compareTree(Node n1,Node n2){
if(n1==null && n2==null) return true;
return ( n1!=null && n2!=null && n1.key==n2.key && compareTree(n1.left,n2.left) && compareTree(n1.right,n2.right) ) ;
}
public static void main(String[] args){
int[] bstInsertOrder1={8, 10, 14, 3, 6, 4, 1, 7, 13};
int[] bstInsertOrder2={8, 3, 6, 1, 4, 7, 10, 14, 13};
Node n1 = buildBST(bstInsertOrder1);
printTree(n1);
System.out.println();
Node n2 = buildBST(bstInsertOrder2);
printTree(n2);
System.out.println("\nBoth are " + (compareTree(n1,n2)?"same":"different"));
}
public static Node buildBST(int[] insertOrder){
int length = insertOrder.length;
Node[] sortedOrder = new Node[length];
for(int i=0;i<length;i++){
sortedOrder[i] = new Node(insertOrder[i],i);
}
Radix.radixsort(sortedOrder,length);
int[] sortedIndex = new int[length];
for(int i=0;i<length;i++){
sortedOrder[i].max=sortedOrder[i].min=sortedOrder[i].root=i;
sortedIndex[sortedOrder[i].arrivalTime]=i;
}
for (int i=length-1;i>0;i--){
int j = sortedIndex[i];
int min=sortedOrder[j].min-1,max=sortedOrder[j].max+1;
Node n=null,n1;
if(min>=0){
n = sortedOrder[sortedOrder[min].root];
}
if(max<length){
n1=sortedOrder[sortedOrder[max].root];
if(n==null){
n=n1;
}
else{
n=(n.arrivalTime>n1.arrivalTime)?n:n1;
}
}
n1=sortedOrder[j];
if(n.key<n1.key){
n.right=n1;
n.max=n1.max;
sortedOrder[n.max].root=sortedOrder[n.min].root;
}
else{
n.left=n1;
n.min=n1.min;
sortedOrder[n.min].root=sortedOrder[n.max].root;
}
}
return sortedOrder[sortedIndex[0]];
}
static class Radix {
static int getMax(Node[] arr, int n) {
int mx = arr[0].key;
for (int i = 1; i < n; i++)
if (arr[i].key > mx)
mx = arr[i].key;
return mx;
}
static void countSort(Node[] arr, int n, int exp) {
Node output[] = new Node[n]; // output array
int i;
int count[] = new int[10];
Arrays.fill(count, 0);
for (i = 0; i < n; i++)
count[(arr[i].key / exp) % 10]++;
for (i = 1; i < 10; i++)
count[i] += count[i - 1];
for (i = n - 1; i >= 0; i--) {
output[count[(arr[i].key / exp) % 10] - 1] = arr[i];
count[(arr[i].key / exp) % 10]--;
}
for (i = 0; i < n; i++)
arr[i] = output[i];
}
static void radixsort(Node[] arr, int n) {
int m = getMax(arr, n);
for (int exp = 1; m / exp > 0; exp *= 10)
countSort(arr, n, exp);
}
}
}
You can check the detailed explaining comparing two binary trees(not just BST) at Determine if two binary trees are equal. It is easy to create BST from the arrays and then run the algorithm in the mentioned questions.
IMO, you can sort one array and do a binary search from the second array to the sorted array, meanwhile, make sure that you are using every element. It will cost you mlogn.
check if it will create the same bst?
Yes.
start taking the first element as root and keep the number which is greater than root to the right and smaller than root to the left.
if you follow the above procedure you will observe that both the trees are identical.
The point may be to compare permutations of the sub-segments of one array with the respective subsegments of the other array (think level order):
starting with the first element in the array, for i=0 to some n, group the elements in sets of 2^i
2^0 = 1: the first element is the root -- must start both arrays:[50].
2^1 = 2: any permutation of the next 2 elements is fine:
[25,75] or [75,25]
2^2=4: any permutation of the next 4 elements is fine:
[10, 35, 60, 85] or [60, 35, 10, 85] or ...
2^3=8: any permutation of the next 8 elements is fine:
[5, 16, 30, 40, ….
so on to 2^n until the arrays are empty. respective subsegments must have the same number of elements.