鉴于已知根的2棵树,我们如何才能有效地确定树是否同构?我们只关心树的形状,而不关心节点的值。如果通过重命名其节点可以将一棵树转换为另一棵树,则树是同构的。算法不需要在100%的时间内都是正确的,因此只要哈希冲突很少,我们就可以使用散列。
编辑:找到解决方案,从这篇文章中删除了不必要的混乱
答案 0 :(得分:0)
经过大量的工作和一些帮助,我想出了一个O(n log n)解决方案,这个解决方案在100%的时间里都是正确的。它基于2个想法:
创意1:树可以表示为列出其子树的String。例如,叶子可以表示为“L”。具有2片叶子的树可以表示为“(L),(L)”。具有2个叶子的子树的树可以表示为“((L),(L))”等。这种方法的问题是大树将导致长的重复字符串,这将减慢算法下来。
创意2:字符串可以在hashmap中编入索引。我们可以为该字符串分配一个索引号,而不是像“((L),(L))”一样,我们可以将这个子树和所有相同的子树引用“2”,而不是使用字符串表示。字符串是散列映射中的键,值是分配给这些字符串的唯一整数。
以下是从第一棵树构建hashmap的代码:
我们的第一个电话应该是fill(root, -1, 1)
public static int fill(int current, int previous, int height) {
ArrayList<Integer> subtrees = new ArrayList<>();
for (int next : edges[current]) {
if (next == previous) continue;
int subtree = fill(next, current, height+1);
subtrees.add(subtree);
}
// We have to sort subtrees for "2,4" and "4,2" to be considered the same
Collections.sort(subtrees);
StringBuilder sb = new StringBuilder(height + ".");
for (Integer subtree : subtrees) {
sb.append(subtree +",");
}
String key = new String(sb);
if (map.containsKey(key)) return map.get(key);
int index = map.size(); // assigning next available number
map.put(key, index);
return index;
}
我们现在可以调用树2的填充(用树2信息替换“边缘”,保持原样的HashMap)。如果它返回相同的整数,则树匹配。
非常感谢http://logic.pdmi.ras.ru/~smal/files/smal_jass08_slides.pdf
答案 1 :(得分:0)
你也可以使用David Matula的Tree - Integer Bijection,它将树映射为整数。
这是一种为每棵树分配唯一自然数的方法。
以下是前32棵树的例子:
有关算法的演练,请参阅本文档中的练习:http://williamsharkey.com/integer-tree-isomorphism.pdf