@@ -38,8 +38,8 @@ public int id() {
38
38
return id ;
39
39
}
40
40
41
- public boolean isLeaf () {
42
- return children . size () == 0 ;
41
+ public TreeNode parent () {
42
+ return parent ;
43
43
}
44
44
45
45
public List <TreeNode > children () {
@@ -52,23 +52,48 @@ public String toString() {
52
52
}
53
53
}
54
54
55
- private static TreeNode rootTree (List <List <Integer >> graph , int rootId ) {
56
- TreeNode root = new TreeNode (rootId );
57
- return buildTree (graph , root , /*parent=*/ null );
58
- }
55
+ // Determines if two unrooted trees are isomorphic
56
+ public static boolean treesAreIsomorphic (List <List <Integer >> tree1 , List <List <Integer >> tree2 ) {
57
+ if (tree1 .isEmpty () || tree2 .isEmpty ()) {
58
+ throw new IllegalArgumentException ("Empty tree input" );
59
+ }
59
60
60
- // Do dfs to construct rooted tree.
61
- private static TreeNode buildTree (List <List <Integer >> graph , TreeNode node , TreeNode parent ) {
62
- for (int childId : graph .get (node .id )) {
63
- // Ignore adding an edge pointing back to parent.
64
- if (parent != null && childId == parent .id ) continue ;
61
+ List <Integer > centers1 = findTreeCenters (tree1 );
62
+ List <Integer > centers2 = findTreeCenters (tree2 );
65
63
66
- TreeNode child = new TreeNode ( childId , node );
67
- node . addChildren ( child );
64
+ TreeNode rootedTree1 = rootTree ( tree1 , centers1 . get ( 0 ) );
65
+ String tree1Encoding = encode ( rootedTree1 );
68
66
69
- buildTree (graph , child , node );
67
+ for (int center : centers2 ) {
68
+ TreeNode rootedTree2 = rootTree (tree2 , center );
69
+ String tree2Encoding = encode (rootedTree2 );
70
+
71
+ if (tree1Encoding .equals (tree2Encoding )) {
72
+ return true ;
73
+ }
70
74
}
71
- return node ;
75
+ return false ;
76
+ }
77
+
78
+ private static boolean areIsomorphic (TreeNode root1 , TreeNode root2 ) {
79
+ return encode (root1 ).equals (encode (root2 ));
80
+ }
81
+
82
+ // Constructs the canonical form representation of a tree as a string.
83
+ public static String encode (TreeNode node ) {
84
+ if (node == null ) {
85
+ return "" ;
86
+ }
87
+ List <String > labels = new LinkedList <>();
88
+ for (TreeNode child : node .children ()) {
89
+ labels .add (encode (child ));
90
+ }
91
+ Collections .sort (labels );
92
+ StringBuilder sb = new StringBuilder ();
93
+ for (String label : labels ) {
94
+ sb .append (label );
95
+ }
96
+ return "(" + sb .toString () + ")" ;
72
97
}
73
98
74
99
private static List <Integer > findTreeCenters (List <List <Integer >> tree ) {
@@ -85,9 +110,7 @@ private static List<Integer> findTreeCenters(List<List<Integer>> tree) {
85
110
86
111
int processedLeafs = leaves .size ();
87
112
88
- // Remove leaf nodes and decrease the degree of
89
- // each node adding new leaf nodes progressively
90
- // until only the centers remain.
113
+ // Iteratively remove all leaf nodes layer by layer until only the centers remain.
91
114
while (processedLeafs < n ) {
92
115
List <Integer > newLeaves = new ArrayList <>();
93
116
for (int node : leaves ) {
@@ -104,43 +127,23 @@ private static List<Integer> findTreeCenters(List<List<Integer>> tree) {
104
127
return leaves ;
105
128
}
106
129
107
- // Determines if two unrooted trees are isomorphic
108
- public static boolean treesAreIsomorphic (List <List <Integer >> tree1 , List <List <Integer >> tree2 ) {
109
- if (tree1 .isEmpty () || tree2 .isEmpty ()) {
110
- throw new IllegalArgumentException ("Empty tree input" );
111
- }
112
-
113
- List <Integer > centers1 = findTreeCenters (tree1 );
114
- List <Integer > centers2 = findTreeCenters (tree2 );
115
-
116
- TreeNode rootedTree1 = rootTree (tree1 , centers1 .get (0 ));
117
- for (int center : centers2 ) {
118
- if (areIsomorphic (rootedTree1 , rootTree (tree2 , center ))) {
119
- return true ;
120
- }
121
- }
122
- return false ;
130
+ private static TreeNode rootTree (List <List <Integer >> graph , int rootId ) {
131
+ TreeNode root = new TreeNode (rootId );
132
+ return buildTree (graph , root , /*parent=*/ null );
123
133
}
124
134
125
- private static boolean areIsomorphic (TreeNode root1 , TreeNode root2 ) {
126
- return encode (root1 ).equals (encode (root2 ));
127
- }
135
+ // Do dfs to construct rooted tree.
136
+ private static TreeNode buildTree (List <List <Integer >> graph , TreeNode node , TreeNode parent ) {
137
+ for (int childId : graph .get (node .id )) {
138
+ // Ignore adding an edge pointing back to parent.
139
+ if (parent != null && childId == parent .id ) continue ;
128
140
129
- // Constructs the canonical form representation of a tree as a string.
130
- public static String encode (TreeNode node ) {
131
- if (node == null ) {
132
- return "" ;
133
- }
134
- List <String > labels = new LinkedList <>();
135
- for (TreeNode child : node .children ()) {
136
- labels .add (encode (child ));
137
- }
138
- Collections .sort (labels );
139
- StringBuilder sb = new StringBuilder ();
140
- for (String label : labels ) {
141
- sb .append (label );
141
+ TreeNode child = new TreeNode (childId , node );
142
+ node .addChildren (child );
143
+
144
+ buildTree (graph , child , node );
142
145
}
143
- return "(" + sb . toString () + ")" ;
146
+ return node ;
144
147
}
145
148
146
149
/* Graph/Tree creation helper methods. */
0 commit comments