記事ディレクトリ
1. タイトル
バイナリ ツリー内の 2 つのノードの最初の共通祖先を見つけるアルゴリズムを設計して実装します。他のノードを他のデータ構造に格納してはなりません。注: これは必ずしも二分探索ツリーである必要はありません。
たとえば、次のようなバイナリ ツリーがあるとします。 root = [3,5,1,6,2,0,8,null,null,7,4]
3
/ \
5 1
/ \ / \
6 2 0 8
/ \
7 4
例 1:
入力: root = [3,5,1,6,2,0,8,null,null,7,4]、p = 5、q = 1
出力: 3
説明:ノード 5 とノード 1 の最も近い共通祖先ノード3です。
例 2:
入力: root = [3,5,1,6,2,0,8,null,null,7,4]、p = 5、q = 4
出力: 5
説明:ノード 5 とノード 4 の最も近い共通祖先ノード5です。定義により、最も近い共通の祖先ノードがノード自体になる可能性があるためです。
例証します:
すべてのノード値は一意です。
p と q は異なるノードであり、両方とも指定されたバイナリ ツリーに存在します。
2. C# の問題の解決策
基本的な考え方は、ツリーを事後順序で走査することです。つまり、最初に子ノードにアクセスしてから、そのノードにアクセスします。したがって、これはボトムアップの走査になります。ノードを処理するとき、左と右のサブツリーの結果が返されます。が知られています。特定の状況の対応する処理は次のとおりです。
node
/ \
left right
- ノードが null です: null を返します。
- ノードは p または q です。
- 左と右のいずれかが p または q の場合、それはツリーが p と q を見つけたことを意味し、ノードを返し、それが見つかったことをマークします。
- 左も右も p または q ではありません。これは最初のものが見つかったことを意味し、ノード自体を返すだけです。
- ノードが p または q ではありません:
- 左と右は両方とも p または q です。これは、ツリーが p と q を見つけ、ノードが返され、見つかったとマークされることを意味します。
- left は p または q ですが、right はそうではありません。 return left は、ツリーが 1 つだけ見つかったことを示します。
- right は p または q ですが、left はそうではありません。right を返し、ツリーが 1 つだけ見つかったことを示します。
- 左も右も p または q ではない場合: null を返し、見つからないことを示します。
- サブツリーが見つかったことがマークされている場合は、左右のうち null でないものが直接返され、その方が最初の共通の親を記録します。
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
bool rt = false;
return Partition(root, p, q, ref rt);
}
// DFS 递归,bool rt 用于记录是否已同时找到 p、q
public TreeNode Partition(TreeNode node, TreeNode p, TreeNode q, ref bool rt) {
if (node == null) return null; // 情况 1
TreeNode left = Partition(node.left, p, q, ref rt); // 左子树结果
TreeNode right = Partition(node.right, p, q, ref rt); // 右子树结果
if (rt) return left == null ? right : left; // 已找到结果,即情况 4
// 没找到结果,分为以下几种情况
TreeNode result = null;
if (node == p || node == q) {
// 情况 2
if (left == p || left == q || right == p || right == q) rt = true; // 情况 2.1
result = node; // 返回结果为自己
}
else if (left == p || left == q) {
if (right == p || right == q) // 情况 3.1
{
rt = true; result = node; }
else result = left; // 情况 3.2
}
else if (right == p || right == q) // 情况 3.3
result = right;
return result; // 情况 3.4
}
}
- 時間計算量: O ( n ) O(n)O ( n )。
- 空間計算量: O ( n ) O(n)O ( n )。