Как утверждали другие, вам нужно будет пересечь данные деревья, но с дополнительным условием, что пересекающиеся пути должны заканчиваться листом в обоих деревьях.
Вы можете сделать это, пройдя оба дерева в тандеме. Это может быть обход в глубину.
Я предполагаю, что значения узлов не обязательно должны быть уникальными. Чтобы избежать того, что дочерние элементы одного узла должны сравниваться со всеми дочерними элементами другого узла, элементы одного уровня могут быть отсортированы по их значению. Таким образом, дочерние элементы двух узлов можно сравнивать за линейное время. Из-за сортировки весь алгоритм выполняется в O (nlogn) . Если значения уникальны в одном дереве, то потомки могут быть хешированы по их значениям, что делает алгоритм O (n) . Но, как указано, я буду использовать go для варианта, в котором разрешены повторяющиеся значения:
Вот реализация в JavaScript:
class Node {
constructor(value, ...children) {
this.value = value;
// sort the children by their value
this.children = children.sort();
}
commonPaths(node) {
if (this.value !== node.value) return [];
if (this.children.length + node.children.length == 0) return [this.value];
let result = [], i = 0, j = 0;
while (i < this.children.length && j < node.children.length) {
let a = this.children[i], b = node.children[j];
for (let path of a.commonPaths(b)) result.push([this.value, ...path]);
i += (a.value <= b.value); // boolean converts to 0 or 1
j += (a.value >= b.value);
}
return result;
}
toString() { return this.value }
}
// Create the trees given in the question
let tree1 = new Node("a",
new Node("b", new Node("e")),
new Node("c", new Node("f")),
new Node("d", new Node("g"), new Node("h"))
);
let tree2 = new Node("a",
new Node("1", new Node("x")),
new Node("d", new Node("g")),
new Node("z")
);
let tree3 = new Node("a",
new Node("x", new Node("s")),
new Node("y")
);
// Get common paths of pairs of these trees
console.log(tree1.commonPaths(tree2));
console.log(tree1.commonPaths(tree3));