これは、バイナリ ツリー内の 2 つのノードの最も低い共通の祖先を非再帰的に見つけるために思いついたアルゴリズムです。基本的な戦略は次のとおりです。
- 辞書/ハッシュテーブルを使用してツリーを保存します。各キーと値のペアは、ノードとその親を表します。
- 2 つのノードのそれぞれから始めて、各ノードの値を表す変数をその親の値に設定し、通過した値をハッシュセット (2 つのノードごとに 1 つ) に格納することによって、ツリーを上っていきます。
- 次の条件のいずれかが満たされると、検索は完了します。(a) 2 つのノードの値が等しい。または (b) 2 つのパスが互いに交差するとき (つまり、ノード 1 のトラバースされた値のハッシュセットにノード 2 の現在の値が含まれる、またはその逆)。または (c) 渡されたノードがツリーに存在しません (この場合、アルゴリズムは終了し、-1 を返します)。
私の理解では、アルゴリズムの最悪の場合の時間と空間の複雑さは O(log(n)) です。これは、ハッシュセットに 2 * 以上の高さのトラバーサルを行ったり、2 * 以上の高さの値を格納したりする必要がないためです (そして、ハッシュセットとツリー辞書のルックアップ時間は O(1)) です。
以下は私のコード(C#)です。私の分析が正しいかどうか、またはこれを行うためのより効率的な(非再帰的な)方法があるかどうかを教えてください:
int LowestCommonAncestor(int value1, int value2, Dictionary<int, int> tree)
{
var value1Visited = new HashSet<int>();
var value2Visited = new HashSet<int>();
while (true)
{
if (value1 == value2) return value1;
if (value1Visited.Contains(value2)) return value2;
if (value2Visited.Contains(value1)) return value1;
int nextValue1;
int nextValue2;
if (tree.TryGetValue(value1, out nextValue1))
{
//Walk node 1 up the tree:
value1 = nextValue1;
value1Visited.Add(value1);
}
else
{
//Node doesn't exist in tree:
return -1;
}
if (tree.TryGetValue(value2, out nextValue2))
{
//Walk node 2 up the tree:
value2 = nextValue2;
value2Visited.Add(value2);
}
else
{
//Node doesn't exist in tree:
return -1;
}
}
}