Как найти самые большие общие поддеревья в множественном дереве

1

В последнее время я сталкиваюсь с проблемой алгоритма: дерево определяется как

public class Node 
{
    int id;      
    private final List<Node> children;
    Node(int id) {
        this.id = id;
        this.children = new ArrayList<>();
    }      
} 

Два поддеревья являются общими, если их структура идентична. Самые большие общие поддеревья максимизируют количество узлов в каждом отдельном поддереве. Итак, как найти общий поддерево maxmum (идентификатор каждого узла не имеет значения, только структура поддеревьев будет одинаковой). Если существуют отдельные группы поддеревьев, которые имеют общий размер с одинаковым максимальным размером, нам следует вернуть корневые узлы из всех поддеревьев.

Моя идея состоит в сериализации каждого поддерева в уникальную строку с использованием BFS. После того, как мы получим все строки, сортируем их и сравниваем, какие два равны. Итак, ниже мой код. Мой вопрос заключается в том, что сериализация каждого поддерева вызывает много накладных расходов, есть ли другая идея решить эту проблему в более сложной временной сложности.

public static List<Node> getLargestCommonSubtrees(Node root) {
        HashMap<String, ArrayList<Node>> map = new HashMap<String, ArrayList<Node>>();
        LinkedList<Node> queue = new LinkedList<Node>();
        queue.add(root);
        while (!queue.isEmpty()) {
            Node cur = queue.pollFirst();
            String sig = serialize(cur);
            if (map.containsKey(sig)) {
                ArrayList<Node> list = map.get(sig);
                list.add(cur);
                map.put(sig, list);
            } else {
                ArrayList<Node> list = new ArrayList<Node>();
                list.add(cur);
                map.put(sig, list);
            }
            for (int i = 0; i < cur.children.size(); i++) {
                if (cur.children.get(i) != null) {
                    queue.add(cur.children.get(i));
                }
            }
        }
        int max = Integer.MIN_VALUE;
        ArrayList<Node> ans = new ArrayList<Node>();
        for (Entry<String, ArrayList<Node>> e : map.entrySet()) {
            if (e.getKey().length() >= max) {
                if (e.getKey().length() > max) {
                    ans.clear();
                }
                ans.addAll(e.getValue());
            }
        }
        return ans;
    }

private static String serialize(Node n) {
        String signature = "";
        LinkedList<Node> q = new LinkedList<Node>();
        q.add(n);
        if (n.children.size() == 0) {
            signature = "0";
            return signature;
        }
        Node curr = null;
        while (!q.isEmpty()) {
            curr = q.peek();
            q.poll();
            signature += String.valueOf(curr.children.size());
            for (int i = 0; i < curr.children.size(); i++) {
                q.offer(curr.children.get(i));
            }
        }
        return signature;
    }
Теги:
algorithm
data-structures
serialization
tree

1 ответ

0

JoJo, возможно, уже существует эффективный алгоритм для этой или подобной проблемы. Однако вот как я это сделаю.

import java.util.ArrayList;
import java.util.List;


public class Node
{
    //signature = number of Node children + signature of each child     =  total number of all nodes below this Node (including children and children children...etc)
    //
    // for example, a tree would have it signature as
    //             13
    //      1       5        4  
    //      0    1    2    1   1
    //           0   0 0   0   0
    //
    private int signature;

    private int id;      
    private final List<Node> children;
    private Node parent;

    public Node(int id, Node parent) {
        this.id = id;
        this.children = new ArrayList<Node>();
        this.parent = parent;
    }

    //updates signature, should be called every time there is a change to Node.
    private void updateSignature() {
        signature = children.size();

        for(Node childNode : children) {
            signature += childNode.signature;
        }

        //tell parent to update it signature
        if(parent != null) {
            parent.updateSignature();
        }
    }

    //compares two trees to check if their structure is similar
    private boolean hasSameStructureAs(Node otherNode) {
        return otherNode != null && signature == otherNode.signature;
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню