假设我有二叉树A和B,我想知道A是否是B的“部分”。我不只是在讨论子树。我想知道的是,B是否具有A所做的所有节点和边缘。
我的想法是,因为树本质上是一个图形,我可以将这个问题视为子图同构问题(即检查A是否是B的子图)。但根据维基百科,这是一个NP完全问题。
http://en.wikipedia.org/wiki/Subgraph_isomorphism_problem
我知道您可以使用O(n)算法检查A是否是B的子树(例如,使用预序和顺序遍历将树展平为字符串并检查子字符串)。我试图稍微修改一下,看看我是否也可以测试“部件”,但无济于事。这就是我被困住的地方。
除了使用子图同构外,还有其他方法可以查看此问题吗?我认为必须有更快的方法,因为二叉树更受限制,图形版本更简单。
提前致谢!
编辑:我意识到,对于我的问题,即使是强力方法的最坏情况也只需要O(m * n),这是多项式的。所以我想这毕竟不是NP完全问题。然后我的下一个问题是,是否存在比O(m * n)更快的算法?答案 0 :(得分:2)
我会分两步来解决这个问题:
A
中找到B
的根(DFS的BFS)A
中是否包含B
(给出该起始节点),如下所示(我编写了相同的疯狂伪语言,因为您没有指定语言。我认为这应该是可以理解的,无论你的背景如何)。请注意,a
是A
(最初是根)的节点,b
是B
的节点(最初是步骤1中找到的节点)
function checkTrees(node a, node b) returns boolean
if a does not exist or b does not exist then
// base of the recursion
return false
else if a is different from b then
// compare the current nodes
return false
else
// check the children of a
boolean leftFound = true
boolean rightFound = true
if a.left exists then
// try to match the left child of a with
// every possible neighbor of b
leftFound = checkTrees(a.left, b.left)
or checkTrees(a.left, b.right)
or checkTrees(a.left, b.parent)
if a.right exists then
// try to match the right child of a with
// every possible neighbor of b
leftFound = checkTrees(a.right, b.left)
or checkTrees(a.right, b.right)
or checkTrees(a.right, b.parent)
return leftFound and rightFound
关于运行时间:让m
为A
中的节点数,n
为B
中的节点数。第一步中的搜索需要O(n)
次。第二步的运行时间取决于我做出的一个重要假设,但这可能是错误的:我假设A
的每个节点最多等于 {{1}的一个节点}}。如果是这种情况,第二步的运行时间为B
(因为您永远不能在错误的方向上搜索太远)。因此总运行时间为O(m)
。
在写下我的假设时,我开始怀疑这是不是过于简化了你的情况......
答案 1 :(得分:0)
你可以自下而上地比较树木:
如果你没有失败,你就会成功; - )。
算法的主要部分在O(e_B)
中运行 - 在最坏的情况下,B中的所有边都被访问了恒定次数。叶节点匹配将在O(n_A * log n_B)
中运行,如果有B个顶点被排序,O(n_A * log n_A + n_B * log n_B + n) = O(n_B * log n_B)
(对每个节点集进行排序,此后立即扫描结果)否则。
编辑: 重新阅读你的问题,上面提到的第2步更容易,因为对于A,B中的匹配节点,他们的父母也必须匹配(否则边缘集之间会出现不匹配)。当然,对最坏情况的运行时间没有影响。