鉴于两个二进制树 T1和T2,是否有任何有效的算法来检查T1是否是T2的子树?二叉树是有序和标记为,即每个节点都有一个标签,左/右子节点不能交换。
例如,T1:是T2的子树:
朴素算法在O(| T1 | * | T2 |)中运行,只需遍历T2的每个节点并检查T1是否可以在该节点上匹配。
O(| T1 | + | T2 |)可能吗?
答案 0 :(得分:0)
子树(C,(D),(B))由两个向上链路组成,D-(L)> C和B-(R)> C,其中L和R区分左右链路。具有n个叶子的任何子树由n个向上序列组成,每个子序列从叶子开始并在子树的根处结束,序列记录节点的字母以及它向上移动的链接的左或右性质。 / p>
构建一个http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm字符串匹配器来识别这些序列,然后在较大树的路径上运行它,从树叶开始到其根部结束。
当找到Aho-Corasick匹配时,标记匹配以及匹配它的序列的最高节点上的匹配类型。如果您发现较大树的节点累积了您在Aho-Corasick匹配器中构建的每个模式的集合,则此节点是您尝试查找的较小子树的副本的根。
答案 1 :(得分:0)
有一个算法O(kT1 + T2),首先遍历T2找到其值等于T1的根值的所有节点,假设我们有k个这样的节点,这个T2的遍历取O( T2)。然后,对于每个节点,检查它是否与T1匹配,这需要O(kT1)。如果T2是唯一的或者只有一个节点等于T1的根,则复杂度恰好是O(T1 + T2)。在T2中查找T1根节点的代码如下:
void do_find_nodes(node* root, T value, std::vector<node *>& nodes)
{
if(root)
{
if(root->val == value)
nodes.push_back(root);
do_find_nodes(root->left);
do_find_nodes(root->right);
}
}
void find_nodes(node *root, T value)
{
std::vector<node *> nodes;
do_find_nodes(root, value, nodes);
}
调用find_nodes()将为T2中的所有节点提供其值等于T1的根,然后您可以检查每个节点是否与T1匹配。