给定两个大小为N的未排序数组,我们将确定从它们构造的二进制搜索树是否相等。
因此,数组的元素被选中并插入到基本(无平衡,无红黑,无任何)二叉搜索树中。 直接给出两个数组,我们可以确定它们是否会产生相同的二进制搜索树。
有一个明显的O(N 2 )最坏情况时间复杂度解决方案:构造两棵树,并比较它们的相等性。
是否有O(N)或O(N log N)解决方案?
我想要提取的问题的想法是:BST的构造取决于元素的相对位置。例如,如果在一个数组中有一个紧邻20的值为51的元素,则在另一个数组中必须没有20到51之间的元素才能使树相等(否则20的右子将是该数字,而不是51 )。
我确实尝试了几种方法:
帮助,非常感谢解决此问题的任何提示。
答案 0 :(得分:1)
我认为你可以通过使用range minimum query构建二叉树来改进从O(N ^ 2)到O(NlogN)的天真方法。
假设我们要为数组A构建二叉树。
这个想法是首先构造一个数组B,其中B [i]是A中第i个最大元素的位置。这可以通过在O(NlogN)中排序来完成。
然后,我们可以在阵列B上使用范围最小查询,以允许我们找到给定范围a< = i< = b的B [i]的最小值。换句话说,这让我们找到A中的第一个位置,其中我们在第一个和第二个最大元素之间的范围内有一个值。RMQ需要时间O(N)进行预处理,然后可以及时回答查询O(1)。
然后我们可以递归地找到每个元素的左右子元素(如果有的话)并检查它们是否匹配。
假设两个数组是A和A2,为简单起见,我们假设A,A2已被预处理,使得第i个最大元素等于i。
如果find_children(1,N)为True,则树是相同的:
find_children(low,high)
if high==low
return True
node = A[RMQ(low,high)]
return node == A2[RMQ2(low,high)]
and find_children(low,node-1)
and find_children(node+1,high)
对于树中的每个节点(和空子指针)调用此函数一次,因此需要时间O(N)。
总的来说,这是O(NlogN),因为预处理排序需要O(NlogN)。
假设我们已将元素20和51输入到二叉树中。然后我们将有20个是根,51个是正确的孩子。要找到51的左子元素,我们需要找到数组中第一个元素,其值大于20且小于51.该值由我们应用于范围20 + 1-> 51的范围最小查询给出。 -1
因此,我们可以更快地找到所有节点的左右子节点,而不是以自然的方式将它们插入到二叉树中(在理论上最坏的情况下只会更快 - 对于典型示例,其他方法可能更快)。 / p>
答案 1 :(得分:1)
“构造两棵树并进行比较”不一定是O(N ^ 2)。你可以使用辅助数据结构,让你在O(log N)而不是O(N)中找到新节点的位置,这样即使正在构造BST,BST的构造也是O(N log N)是不平衡的。
对于BST中的每个空位置(即节点中的空闲子槽)pos
,存在关联的间隔(a_pos,b_pos)
(其中一个值可能是+/-无穷大),例如当且仅当值在区间内时,才会在v
创建值pos
的新节点。
您可以将间隔存储在平衡间隔树中,以便可以在O(log N)中找到每个新到达值的位置。间隔树的更新也是O(log N),因为您只用两个间隔替换一个间隔。
(实际上,间隔从不重叠,因此辅助结构可以是普通的(平衡的)BST而不是间隔树。)
示例:
采用以下非平衡BST,为数组前缀[1,10,2,9,3,...]构建
1
/ \
a 10
/ \
2 f
/ \
b 9
/ \
3 e
/ \
c d
字母a-f
表示可以放置新节点的可能位置(零叶)。每个字母都有一个相关的间隔,如下所示:
[-inf,1] -> a
[1,2] -> b
[2,3] -> c
[3,9] -> d
[9,10] -> e
[10, +inf] -> f
值v
的新节点将添加到由v
所属的时间间隔确定的位置的BST中。 Zero将以a
结束,5 d
结束,依此类推。关键的想法是将这些信息存储在树外。
如果您可以有效地表示上表(包含指向实际树节点的链接),则向树添加新节点将采用O(访问表)+ O(1)。 O(1)表示将节点添加到非平衡BST中,因为您已经知道放置它的位置。添加5不需要与1,10,2,9和3进行比较,而是在表格中查找并直接放在d
。
放置新节点后,显然还需要更新表。表示表的数据结构可以是间隔树(http://en.wikipedia.org/wiki/Interval_tree)。
答案 2 :(得分:0)
试试这个:
int identical(struct node* a, struct node* b)
{
if (a==NULL && b==NULL)
{
return(true);
}
else if (a!=NULL && b!=NULL)
{
return(a-> data == b-> data && identical(a->left, b->left) && identical(a->right, b->right));
}
else
return(false);
}
答案 3 :(得分:0)
我提出了以下代码。虽然分区效率低下,但它工作正常。
bool isBST (vector<int> vec1, vector<int> vec2) {
if (vec1.size() == 0 && vec2.size() == 0)
return true;
if (vec1.size() != vec2.size())
return false;
if (vec1[0] != vec2[0])
return false;
vector<int> temp1;
vector<int> temp2;
vector<int> temp3;
vector<int> temp4;
for (int k = 1; k < vec1.size(); k++) {
if(vec1[k] < vec1[0])
temp1.push_back(vec1[k]);
else
temp2.push_back(vec1[k]);
if(vec2[k] < vec2[0])
temp3.push_back(vec2[k]);
else
temp4.push_back(vec2[k]);
}
return isBST(temp1, temp3) && isBST(temp2, temp4);
}