Skip to content

Commit c7731b2

Browse files
committed
check in the source code
1 parent aaa7e54 commit c7731b2

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace LowestCommonAncestorBTree
8+
{
9+
/// <summary>
10+
/// code review on July 9, 2018
11+
/// Leetcode 236
12+
/// https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/
13+
/// </summary>
14+
class TreeNode
15+
{
16+
public int val;
17+
public TreeNode left;
18+
public TreeNode right;
19+
20+
public TreeNode(int x)
21+
{
22+
left = null;
23+
right = null;
24+
val = x;
25+
}
26+
};
27+
28+
class LowestCommonAncestorB
29+
{
30+
/*
31+
* Leetcode:
32+
* Lowest common ancestor in binary tree
33+
*
34+
* Try a few of implementations - 4 different ones:
35+
* 1. Method A:
36+
* Top down method, using counting method to help
37+
* worst case time O(N^2)
38+
*
39+
* 2. Method B:
40+
* A Bottom-up Approach (Worst case O(n) ):
41+
Using a bottom-up approach, we can improve over the top-down approach
42+
by avoiding traversing the same nodes over and over again.
43+
*/
44+
static void Main(string[] args)
45+
{
46+
var root = new TreeNode(1);
47+
root.left = new TreeNode(2);
48+
root.right = new TreeNode(3);
49+
50+
root.left.left = new TreeNode(4);
51+
root.left.right = new TreeNode(5);
52+
53+
root.right.left = new TreeNode(6);
54+
root.right.right = new TreeNode(7);
55+
56+
var ancestor = LowestCommonAncestor(root, root.right.left, root.left.right);
57+
}
58+
59+
/*
60+
* source code from blog:
61+
* http://articles.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
62+
*
63+
* A Top-Down Approach (Worst case O(n^2) ):
64+
*
65+
* julia's comment:
66+
1. check left subtree count of matching p or q:
67+
0 - no match in left sub tree, so go to check right subtree
68+
1 - found it, the root is the node
69+
2 - continue to left, check
70+
* 2. put the code in the certain order: root, left, right
71+
* so, making it easy to follow.
72+
* two orders:
73+
* 1. check countingProblem return value, from 0 to 1 to 2, increasing order
74+
* 2. using countingProblem calculation take action, "found it", "go left",
75+
* "go right" three choice.
76+
*
77+
* Keep the code in the above order, this way, easy to memorize, explain, and discuss.
78+
*
79+
* 3. Using a easy counting problem to help solve lowest common ancestor (LCA),
80+
* What is the thinking process?
81+
* Here is the scripts Julia makes out:
82+
* Go to visit root first, check it value, null or one of two nodes,
83+
* and then, decide to find LCA, or go left to find it or go right to find it.
84+
*
85+
* But wait, how to decide to find it, or go left/ right, so calculate the left sub tree
86+
* matching count first, use its value to determine.
87+
*
88+
* 4. online judge: (lowest common ancestor in binary search tree, not in binary tree)
89+
* 27 / 27 test cases passed.
90+
Status: Accepted
91+
Runtime: 180 ms
92+
*
93+
*/
94+
public static TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q)
95+
{
96+
if (root == null || p == null || q == null)
97+
return null;
98+
99+
if (root == p || root == q)
100+
return root;
101+
102+
// go left
103+
int leftTreeMatched = findMatches(root.left, p, q);
104+
105+
bool zeroFound = leftTreeMatched == 0;
106+
bool oneFound = leftTreeMatched == 1;
107+
bool twoFound = leftTreeMatched == 2;
108+
109+
if (oneFound)
110+
{
111+
return root;
112+
}
113+
else if (twoFound)
114+
{
115+
return LowestCommonAncestor(root.left, p, q);
116+
}
117+
else if (zeroFound)
118+
{
119+
return LowestCommonAncestor(root.right, p, q);
120+
}
121+
122+
return null;
123+
}
124+
125+
/*
126+
* source code from blog:
127+
* http://articles.leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
128+
* comment from blog:
129+
* A Top-Down Approach (Worst case O(n^2) ):
130+
131+
Let’s try the top-down approach where we traverse the nodes from the top to the bottom.
132+
* First, if the current node is one of the two nodes, it must be the LCA of the two nodes.
133+
* If not, we count the number of nodes that matches either p or q in the left subtree (which
134+
* we call totalMatches). If totalMatches equals 1, then we know the right subtree will contain
135+
* the other node. Therefore, the current node must be the LCA. If totalMatches equals 2, we know
136+
* that both nodes are contained in the left subtree, so we traverse to its left child. Similar
137+
* with the case where totalMatches equals 0 where we traverse to its right child.
138+
*
139+
* Return #nodes that matches P or Q in the subtree.
140+
*
141+
* julia's comment:
142+
* 1. Convert C++ code to C#
143+
* 2. Solve a problem first: counting matches in the tree
144+
* Counting always helps to make decision. Using number to make a decision
145+
* 3. think about the question:
146+
* Can this function only uses two line code?
147+
*
148+
*
149+
*/
150+
private static int findMatches(TreeNode root, TreeNode p, TreeNode q)
151+
{
152+
if (root == null) return 0;
153+
154+
int matches = findMatches(root.left, p, q) + findMatches(root.right, p, q);
155+
156+
if (root == p || root == q)
157+
{
158+
return 1 + matches;
159+
}
160+
else
161+
{
162+
return matches;
163+
}
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)