-
Notifications
You must be signed in to change notification settings - Fork 43
/
SubtreeOfAnotherTree.java
236 lines (196 loc) · 7.25 KB
/
SubtreeOfAnotherTree.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package LeetCodeJava.Tree;
// https://leetcode.com/problems/subtree-of-another-tree/
import LeetCodeJava.DataStructure.TreeNode;
import java.util.ArrayList;
import java.util.List;
public class SubtreeOfAnotherTree {
// V0
// IDEA : DFS + DFS (modified by GPT)
// https://github.com/yennanliu/CS_basics/blob/master/leetcode_python/Tree/subtree-of-another-tree.py#L110
public boolean isSubtree(TreeNode s, TreeNode t) {
if (s == null && t == null) {
return true;
}
if (s == null || t == null) {
return false;
}
/**
* NOTE !!! isSameTree and isSubtree with sub left, sub right tree
*
* e.g.
* isSubtree(s.left, t)
* isSubtree(s.right, t)
*
* -> only take sub tree on s (root), but use the same t (sub root)
*
*
* NOTE !!!
* -> below is "or" logic
*/
return isSameTree(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
}
/** NOTE !!!
*
* isSameTree func is comparing if s, t are the same tree (same structure, val)
*/
private boolean isSameTree(TreeNode s, TreeNode t) {
if (s == null && t == null) {
return true;
}
if (s == null || t == null) {
return false;
}
/**
* NOTE !!!
*
* -> below is "and" logic
*/
return s.val == t.val && isSameTree(s.left, t.left) && isSameTree(s.right, t.right);
}
// V1
// IDEA : DFS
// https://leetcode.com/problems/subtree-of-another-tree/editorial/
public boolean isSubtree_1(TreeNode root, TreeNode subRoot) {
// If this node is Empty, then no tree is rooted at this Node
// Hence, "tree rooted at node" cannot be equal to "tree rooted at subRoot"
// "tree rooted at subRoot" will always be non-empty, as per constraints
if (root == null) {
return false;
}
// Check if the "tree rooted at root" is identical to "tree roooted at subRoot"
if (isIdentical(root, subRoot)) {
return true;
}
// If not, check for "tree rooted at root.left" and "tree rooted at root.right"
// If either of them returns true, return true
// NOTE !!! either left or right tree equals subRoot is acceptable
return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
}
/** NOTE !!! check this help func */
private boolean isIdentical(TreeNode node1, TreeNode node2) {
// If any of the nodes is null, then both must be null
if (node1 == null || node2 == null) {
return node1 == null && node2 == null;
}
// If both nodes are non-empty, then they are identical only if
// 1. Their values are equal
// 2. Their left subtrees are identical
// 3. Their right subtrees are identical
return node1.val == node2.val && isIdentical(node1.left, node2.left) && isIdentical(node1.right, node2.right);
}
// V2
// IDEA : STRING MATCH
// https://leetcode.com/problems/subtree-of-another-tree/editorial/
public boolean isSubtree_2(TreeNode root, TreeNode subRoot) {
// Serialize given Nodes
StringBuilder rootList = new StringBuilder();
serialize(root, rootList);
String r = rootList.toString();
StringBuilder subRootList = new StringBuilder();
serialize(subRoot, subRootList);
String s = subRootList.toString();
// Check if s is in r
return kmp(s, r);
}
// Function to serialize Tree
private void serialize(TreeNode node, StringBuilder treeStr) {
if (node == null) {
treeStr.append("#");
return;
}
treeStr.append("^");
treeStr.append(node.val);
serialize(node.left, treeStr);
serialize(node.right, treeStr);
}
// Knuth-Morris-Pratt algorithm to check if `needle` is in `haystack` or not
private boolean kmp(String needle, String haystack) {
int m = needle.length();
int n = haystack.length();
if (n < m)
return false;
// longest proper prefix which is also suffix
int[] lps = new int[m];
// Length of Longest Border for prefix before it.
int prev = 0;
// Iterating from index-1. lps[0] will always be 0
int i = 1;
while (i < m) {
if (needle.charAt(i) == needle.charAt(prev)) {
// Length of Longest Border Increased
prev += 1;
lps[i] = prev;
i += 1;
} else {
// Only empty border exist
if (prev == 0) {
lps[i] = 0;
i += 1;
} else {
// Try finding longest border for this i with reduced prev
prev = lps[prev - 1];
}
}
}
// Pointer for haystack
int haystackPointer = 0;
// Pointer for needle.
// Also indicates number of characters matched in current window.
int needlePointer = 0;
while (haystackPointer < n) {
if (haystack.charAt(haystackPointer) == needle.charAt(needlePointer)) {
// Matched Increment Both
needlePointer += 1;
haystackPointer += 1;
// All characters matched
if (needlePointer == m)
return true;
} else {
if (needlePointer == 0) {
// Zero Matched
haystackPointer += 1;
} else {
// Optimally shift left needlePointer. Don't change haystackPointer
needlePointer = lps[needlePointer - 1];
}
}
}
return false;
}
// V3
// IDEA : TREE HASH
// https://leetcode.com/problems/subtree-of-another-tree/editorial/
// CONSTANTS
final int MOD_1 = 1000000007;
final int MOD_2 = 2147483647;
// Hashing a Node
long[] hashSubtreeAtNode(TreeNode node, boolean needToAdd) {
if (node == null)
return new long[] { 3, 7 };
long[] left = hashSubtreeAtNode(node.left, needToAdd);
long[] right = hashSubtreeAtNode(node.right, needToAdd);
long left1 = (left[0] << 5) % MOD_1;
long right1 = (right[0] << 1) % MOD_1;
long left2 = (left[1] << 7) % MOD_2;
long right2 = (right[1] << 1) % MOD_2;
long[] hashpair = { (left1 + right1 + node.val) % MOD_1,
(left2 + right2 + node.val) % MOD_2 };
if (needToAdd)
memo.add(hashpair);
return hashpair;
}
// Vector to store hashed value of each node.
List<long[]> memo = new ArrayList<>();
public boolean isSubtree_4(TreeNode root, TreeNode subRoot) {
// Calling and adding hash to List
hashSubtreeAtNode(root, true);
// Storing hashed value of subRoot for comparison
long[] s = hashSubtreeAtNode(subRoot, false);
// Check if hash of subRoot is present in memo
for (long[] m : memo) {
if (m[0] == s[0] && m[1] == s[1])
return true;
}
return false;
}
}