BST来自​​两个未排序的数组

时间:2012-03-22 06:02:49

标签: algorithm binary-tree

在一次采访中提到了这个问题: 给定两个未排序的数组,检查它是否会创建相同的bst。 例如:2,1,4,0​​和2,1,0,4都会形成相同的BST。

     2
    / \
   1   4
  /
 0

请提出一些好的算法。

7 个答案:

答案 0 :(得分:4)

  • 取第一个元素 - 这将是根(在上面的例子中是2)
  • 所有小于根元素的元素在两个数组中都应以相同的顺序出现
    • 在上面的例子中,0和1是比根元素小的元素。
    • 在第一个数组中,顺序为1,0
    • 在第二个数组中维护相同的顺序。所以两者都形成相同的结构
  • 所有大于根元素的元素应该在两个数组中以相同的顺序出现

    • 在上面的示例中,4是唯一大于2的元素。它出现在两个数组中。 因此两个阵列都创建了BST,它们在结构上是相同的。
  • 当然,第一个条件是两个数组都应包含相同的元素,但顺序不同。

因此,这可以在线性时间内解决。

伪代码就像这样:

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;
}

答案 1 :(得分:1)

我同意Peter和Algorist所描述的想法。但我相信每个节点的子树(由小于该节点的数组表示,并且大于它的数组)也需要以这种方式检查。例如,621407和621047产生相同的BST,但624017不产生。该函数可以递归写入。

添加了示例代码:

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);
}

功能分区与您在快速排序中使用的功能分区相同。 显然,T(n)= 2T(n / 2)+ O(n),这导致时间复杂度T(n)= O(nlogn)。 由于递归,空间复杂度为O(logn)

答案 2 :(得分:0)

您可以查看Determine if two binary trees are equal比较两个二叉树(不仅仅是BST)的详细说明。从阵列中创建BST很容易,然后在上述问题中运行算法。

答案 3 :(得分:0)

IMO,你可以对一个数组进行排序,并从第二个数组到排序数组进行二进制搜索,同时确保使用每个元素。这将花费你mlogn。

答案 4 :(得分:0)

检查它是否会创建相同的bst?

开始以root身份获取第一个元素,并保持数字大于root的数字,小于root的数字。

如果按照上述步骤操作,您会发现两棵树都是相同的。

答案 5 :(得分:0)

重点可能是将一个数组的子段的排列与另一个数组的相应子段进行比较(思考级别顺序):

从数组中的第一个元素开始,对于i = 0到某个n,将元素分组为2 ^ i

2 ^ 0 = 1:第一个元素是根 - 必须启动两个数组:[50]。

2 ^ 1 = 2:接下来的2个元素的任何排列都很好:

[25,75] or [75,25]

2 ^ 2 = 4:接下来的4个元素的任何排列都很好:

[10, 35, 60, 85] or [60, 35, 10, 85] or ...

2 ^ 3 = 8:接下来的8个元素的任何排列都很好:

 [5, 16, 30, 40, ….

等到2 ^ n,直到数组为空。 相应的子分段必须具有相同数量的元素。

答案 6 :(得分:0)

1)使用计数或基数排序对数组进行排序。

2)使用我们的排序数组构建树并给出未排序的数组(用于检查插入顺序)。它将保留树的结构。

3)比较两棵树。

所有这些都可以在线性时间内完成 - O(n)。

代码:

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);
    }
}

}