最近,我遇到了一个算法问题:树被定义为
public class Node
{
int id;
private final List<Node> children;
Node(int id) {
this.id = id;
this.children = new ArrayList<>();
}
}
如果两个子树的结构完全相同,则它们是共同的。最大的公共子树最大化每个子树中的节点数。那么如何找到maxmum公共子树(每个节点的id无关紧要,只是子树的结构是相同的)。如果存在具有相同最大大小的单独子树组,那么我们应该从所有子树返回根节点。
我的想法是使用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;
}
答案 0 :(得分:0)
import java.util.ArrayList;
import java.util.List;
public class Node
{
//signature = number of Node's children + signature of each child = total number of all nodes below this Node (including children and children's children...etc)
//
// for example, a tree would have it's 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's 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;
}
}