-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path236LowestCommonAncestorBTree.cs
302 lines (259 loc) · 10.9 KB
/
236LowestCommonAncestorBTree.cs
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LowestCommonAncestorBTree
{
class TreeNode
{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) {
left = null;
right = null;
val = x;
}
};
class LowestCommonAncestorB
{
/*
* Leetcode:
* Lowest common ancestor in binary tree
*
* Try a few of implementations - 4 different ones:
* 1. Method A:
* Top down method, using counting method to help
* worst case time O(N^2)
*
* 2. Method B:
* A Bottom-up Approach (Worst case O(n) ):
Using a bottom-up approach, we can improve over the top-down approach
by avoiding traversing the same nodes over and over again.
*
* 3. Method C:
* Cannot pass leetcode online judge
*
* 4. Method D:
* Cannot pass leetcode online judge
*/
static void Main(string[] args)
{
TreeNode n1 = new TreeNode(1);
n1.left = new TreeNode(2);
n1.right = new TreeNode(3);
n1.left.left = new TreeNode(4);
n1.left.right = new TreeNode(5);
n1.right.left = new TreeNode(6);
n1.right.right = new TreeNode(7);
TreeNode r = lowestCommonAncestorBTree_C(n1, n1.right.left, n1.left.right);
// failed test case
TreeNode n2 = new TreeNode(37);
}
/*
* source code from blog:
* http://articles.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
* comment from blog:
* A Top-Down Approach (Worst case O(n^2) ):
Let’s try the top-down approach where we traverse the nodes from the top to the bottom.
* First, if the current node is one of the two nodes, it must be the LCA of the two nodes.
* If not, we count the number of nodes that matches either p or q in the left subtree (which
* we call totalMatches). If totalMatches equals 1, then we know the right subtree will contain
* the other node. Therefore, the current node must be the LCA. If totalMatches equals 2, we know
* that both nodes are contained in the left subtree, so we traverse to its left child. Similar
* with the case where totalMatches equals 0 where we traverse to its right child.
*
* Return #nodes that matches P or Q in the subtree.
*
* julia's comment:
* 1. Convert C++ code to C#
* 2. Solve a problem first: counting matches in the tree
* Counting always helps to make decision. Using number to make a decision
* 3. think about the question:
* Can this function only uses two line code?
*
*
*/
public static int countingProblem(TreeNode root, TreeNode p, TreeNode q)
{
if (root == null) return 0;
int matches = countingProblem(root.left, p, q) + countingProblem(root.right, p, q);
if (root == p || root == q)
return 1 + matches;
else
return matches;
}
/*
* source code from blog:
* http://articles.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
*
* A Top-Down Approach (Worst case O(n^2) ):
*
* julia's comment:
1. check left subtree count of matching p or q:
0 - no match in left sub tree, so go to check right subtree
1 - found it, the root is the node
2 - continue to left, check
* 2. put the code in the certain order: root, left, right
* so, making it easy to follow.
* two orders:
* 1. check countingProblem return value, from 0 to 1 to 2, increasing order
* 2. using countingProblem calculation take action, "found it", "go left",
* "go right" three choice.
*
* Keep the code in the above order, this way, easy to memorize, explain, and discuss.
*
* 3. Using a easy counting problem to help solve lowest common ancestor (LCA),
* What is the thinking process?
* Here is the scripts Julia makes out:
* Go to visit root first, check it value, null or one of two nodes,
* and then, decide to find LCA, or go left to find it or go right to find it.
*
* But wait, how to decide to find it, or go left/ right, so calculate the left sub tree
* matching count first, use its value to determine.
*
* 4. online judge: (lowest common ancestor in binary search tree, not in binary tree)
* 27 / 27 test cases passed.
Status: Accepted
Runtime: 180 ms
*
*/
public static TreeNode LowestCommonAncestor_A(TreeNode root, TreeNode p, TreeNode q)
{
if (root == null || p == null || q == null )
return null;
if (root == p || root == q)
return root;
// go left
int no = countingProblem(root.left, p, q);
// no: 0, 1, 2
bool goRight = no == 0;
bool foundIt = no == 1;
bool goLeft = no == 2;
// found it! it is root!
if (foundIt)
return root;
// go left
else if (goLeft)
return LowestCommonAncestor_A(root.left, p, q);
// go right
else if (goRight)
return LowestCommonAncestor_A(root.right, p, q);
return null;
}
/*
* source code from blog:
* http://articles.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
*
* A Bottom-up Approach (Worst case O(n) ):
Using a bottom-up approach, we can improve over the top-down approach
by avoiding traversing the same nodes over and over again.
We traverse from the bottom, and once we reach a node which matches one
of the two nodes, we pass it up to its parent. The parent would then test
its left and right subtree if each contain one of the two nodes. If yes, then
* the parent must be the LCA and we pass its parent up to the root. If not, we
* pass the lower node which contains either one of the two nodes (if the left
* or right subtree contains either p or q), or NULL (if both the left and
* right subtree does not contain either p or q) up.
*
* julia's comment:
* 1. Leetcode online judge - lowest common ancestor in binary tree
* 31 / 31 test cases passed.
Status: Accepted
Runtime: 172 ms
*
* */
public static TreeNode LowestCommonAncestor_B(TreeNode root, TreeNode p, TreeNode q)
{
if (root == null)
return null;
if (root == p || root == q)
return root;
TreeNode L = LowestCommonAncestor_B(root.left, p, q);
TreeNode R = LowestCommonAncestor_B(root.right, p, q);
if (L!=null && R!=null) return root; // if p and q are on both sides
return (L!=null) ? L : R; // either one of p,q is on one side OR p,q is not in L&R subtrees
}
/**
* Leetcode:
* Lowest Common Ancestor of a Binary Tree
* source code from the blog:
* http://huangyawu.com/leetcode-lowest-common-ancestor-of-a-binary-tree/
*
*
* julia's comment:
* To my surprise, the checking is much more relaxed than I thought:
* if one of two nodes is visited, then, stop; another node may be in the
* subtree, maybe not; but return the node anyway.
*
* if left, right both are not null - root - one node is in left tree,
one node is in right tree
else if left is null, then, right
else if right not null, then left
*
* Online judge: failed
*
* 29 / 31 test cases passed.
*
* Input:
[37,-34,-48,null,-100,-100,48,null,null,null,null,-54,null,-71,-22,null,null,null,8],
* node with value -100, node with value -71
Output:
37
Expected:
-48
*/
public static TreeNode lowestCommonAncestorBTree_C(TreeNode root, TreeNode p, TreeNode q)
{
if (root == null || root.val == p.val || root.val == q.val)
return root;
TreeNode left = lowestCommonAncestorBTree_C(root.left, p, q);
TreeNode right = lowestCommonAncestorBTree_C(root.right, p, q);
return left == null ? right : right == null ? left : root;
}
/*
* julia's comment:
* 1. leetcode online judge
* lowest common ancestor for binary tree - Question No: 236
*
*
*/
public static TreeNode lowestCommonAncestorBTree_D(TreeNode root, TreeNode p, TreeNode q)
{
bool node1Find = false, node2Find = false;
return findFather(root, p, q, ref node1Find, ref node2Find);
}
/*
* source code from blog:
* http://www.cnblogs.com/chkkch/archive/2012/11/26/2788795.html
* 递归版本:空间O(1),时间O(n)
*
*
* julia's comment:
* convert C++ to C#
*/
public static TreeNode findFather(TreeNode root, TreeNode node1, TreeNode node2, ref bool node1Find, ref bool node2Find)
{
if (root == null)
return null;
bool leftNode1Find = false, leftNode2Find = false;
TreeNode leftNode = findFather(root.left, node1, node2, ref leftNode1Find, ref leftNode2Find);
if (leftNode != null)
return leftNode;
bool rightNode1Find = false, rightNode2Find = false;
TreeNode rightNode = findFather(root.right, node1, node2, ref rightNode1Find, ref rightNode2Find);
if (rightNode != null)
return rightNode;
node1Find = leftNode1Find || rightNode1Find;
node2Find = leftNode2Find || rightNode2Find;
if (node1Find && node2Find)
return root;
if (root == node1)
node1Find = true;
if (root == node2)
node2Find = true;
return null;
}
}
}