Skip to content

Commit fdfb084

Browse files
committed
EquivalentTrees task: add test cases, adjust solution to cover them
1 parent 8f3efb0 commit fdfb084

File tree

3 files changed

+81
-12
lines changed

3 files changed

+81
-12
lines changed

src/main/java/by/andd3dfx/tree/equivalent/EquivalentTrees.java

+23-11
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ public List<Node> findEquivalentSubtrees(Node root) {
3232

3333
// Fill `vocabulary` field of nodes
3434
fillNodeVocabulary(root);
35+
// Fill `subtreeSize` field of nodes
36+
fillSubTreeSize(root);
3537

3638
// Build Set<Character> -> List<Node> map
37-
Map<Set<Character>, List<Node>> voc2Nodes = new HashMap<>();
39+
Map<Set<Character>, List<Node>> voc2NodesMap = new HashMap<>();
3840

3941
Deque<Node> queue = new ArrayDeque<>();
4042
queue.add(root);
@@ -46,23 +48,23 @@ public List<Node> findEquivalentSubtrees(Node root) {
4648
if (current.right != null) {
4749
queue.add(current.right);
4850
}
49-
Set<Character> vocabulary = current.vocabulary;
5051

51-
if (!voc2Nodes.containsKey(vocabulary)) {
52-
voc2Nodes.put(vocabulary, new ArrayList<>());
52+
Set<Character> vocabulary = current.vocabulary;
53+
if (!voc2NodesMap.containsKey(vocabulary)) {
54+
voc2NodesMap.put(vocabulary, new ArrayList<>());
5355
}
54-
voc2Nodes.get(vocabulary).add(current);
56+
voc2NodesMap.get(vocabulary).add(current);
5557
}
5658

57-
return voc2Nodes.values().stream()
58-
.filter(nodesList -> nodesList.size() >= 2)
59-
.sorted((o1, o2) -> o2.stream().mapToInt(nodeToIntFunction()).sum() - o1.stream().mapToInt(nodeToIntFunction()).sum())
60-
.limit(1)
61-
.findFirst().orElse(null);
59+
return voc2NodesMap.values().stream()
60+
.filter(nodes -> nodes.size() >= 2)
61+
.min((o1, o2) -> o2.stream().mapToInt(nodeToIntFunction()).sum() - o1.stream().mapToInt(nodeToIntFunction()).sum())
62+
.map(nodes -> nodes.subList(0, 2))
63+
.orElse(null);
6264
}
6365

6466
private static ToIntFunction<Node> nodeToIntFunction() {
65-
return node -> node.vocabulary.size();
67+
return node -> node.subtreeSize;
6668
}
6769

6870
private Set<Character> fillNodeVocabulary(Node node) {
@@ -76,4 +78,14 @@ private Set<Character> fillNodeVocabulary(Node node) {
7678
}
7779
return node.vocabulary;
7880
}
81+
82+
private int fillSubTreeSize(Node node) {
83+
if (node.left != null) {
84+
node.subtreeSize += 1 + fillSubTreeSize(node.left);
85+
}
86+
if (node.right != null) {
87+
node.subtreeSize += 1 + fillSubTreeSize(node.right);
88+
}
89+
return node.subtreeSize;
90+
}
7991
}

src/main/java/by/andd3dfx/tree/equivalent/Node.java

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class Node {
99
Node right;
1010

1111
Set<Character> vocabulary = new HashSet<>();
12+
int subtreeSize;
1213

1314
public Node(char value) {
1415
this.value = value;

src/test/java/by/andd3dfx/tree/equivalent/EquivalentTreesTest.java

+57-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void findEquivalentSubtreesWhenOneCandidate() {
7979
* </pre>
8080
*/
8181
@Test
82-
public void findEquivalentSubtreesWhenTwoCandidate() {
82+
public void findEquivalentSubtreesSymmetricCase() {
8383
Node node = new Node('A');
8484
node.left = new Node('B');
8585
node.left.left = new Node('X');
@@ -92,6 +92,58 @@ public void findEquivalentSubtreesWhenTwoCandidate() {
9292
assertThat(result, hasItems(node.left, node.right));
9393
}
9494

95+
/**
96+
* <pre>
97+
* A
98+
* / \
99+
* B B
100+
* / \
101+
* X C
102+
* \
103+
* X
104+
* </pre>
105+
*/
106+
@Test
107+
public void findEquivalentSubtreesAsymmetricCase() {
108+
Node node = new Node('A');
109+
node.left = new Node('B');
110+
node.left.left = new Node('X');
111+
node.right = new Node('B');
112+
node.right.right = new Node('C');
113+
node.right.right.right = new Node('X');
114+
115+
List<Node> result = equivalentTrees.findEquivalentSubtrees(node);
116+
117+
assertThat(result.size(), is(2));
118+
assertThat(result, hasItems(node.left, node.right.right));
119+
}
120+
121+
/**
122+
* <pre>
123+
* A
124+
* / \
125+
* B B
126+
* / \
127+
* X X
128+
* \
129+
* X
130+
* </pre>
131+
*/
132+
@Test
133+
public void findEquivalentSubtreesAsymmetricCaseShouldChooseNodesWithMaxSubtreeSize() {
134+
Node node = new Node('A');
135+
node.left = new Node('B');
136+
node.left.left = new Node('X');
137+
node.right = new Node('B');
138+
node.right.right = new Node('X');
139+
node.right.right.right = new Node('X');
140+
141+
List<Node> result = equivalentTrees.findEquivalentSubtrees(node);
142+
143+
assertThat(result.size(), is(2));
144+
assertThat(result, hasItems(node.left, node.right));
145+
}
146+
95147
/**
96148
* <pre>
97149
* A
@@ -101,6 +153,8 @@ public void findEquivalentSubtreesWhenTwoCandidate() {
101153
* E B E
102154
* / / \
103155
* D E D
156+
* / \
157+
* D E
104158
* </pre>
105159
*/
106160
@Test
@@ -116,6 +170,8 @@ public void findEquivalentSubtreesComplexCase() {
116170
root.right.right = new Node('E');
117171
root.right.right.left = new Node('E');
118172
root.right.right.right = new Node('D');
173+
root.right.right.right.left = new Node('D');
174+
root.right.right.right.right = new Node('E');
119175

120176
List<Node> result = equivalentTrees.findEquivalentSubtrees(root);
121177

0 commit comments

Comments
 (0)