二分木における最下位共通祖先
二分木の最下位共通祖先とは何ですか?
の 最下位共通祖先 n1 と n2 の両方を持つツリーの最下位ノードです。 子孫、 ここで、n1 と n2 は、LCA を見つけたいノードです。したがって、ノード n1 と n2 を持つ二分木の LCA は、ルートから最も遠くに位置する n1 と n2 の共有祖先です。
最低共通祖先(LCA)の適用:
ツリー内のノードのペア間の距離を決定するには、n1 から n2 までの距離は、ルートから n1 までの距離に、ルートから n2 までの距離を加え、ルートから最も低い共通点までの距離の 2 倍を引いたものとして計算できます。祖先。
二分木における最下位共通祖先
推奨される実践 バイナリ ツリーの最小共通祖先 試してみましょう。ルートから n1 へ、およびルートから n2 へのパスを保存することによる、二分木内の最下位共通祖先:
このアプローチの考え方は、ルートから n1 へのパスとルートから n2 へのパスを 2 つの別々のデータ構造に保存することです。次に、データ構造に格納されている値を同時に調べて、最初の不一致を探します。
図:
![]()
5 と 6 の LCA を求める
ルートから 5 までのパス = { 1, 2, 5 }
ルートから 6 までのパス = { 1, 3, 6 }
- インデックス0からチェックを開始します。両方の値が一致するため ( pathA[0] = pathB[0] )、次のインデックスに移動します。
- pathA[1] は pathB[1] と等しくなく、不一致があるため、前の値を考慮します。
- したがって、(5,6) の LCA = 1
問題を解決するには、次の手順に従ってください。
- ルートから n1 までのパスを見つけて、ベクトルまたは配列に格納します。
- ルートから n2 へのパスを見つけて、それを別のベクトルまたは配列に格納します。
- 配列の値が同じになるまで両方のパスをたどります。不一致の直前の共通要素を返します。
上記のアルゴリズムの実装は次のとおりです。
C++
// C++ Program for Lowest Common Ancestor> // in a Binary Tree> // A O(n) solution to find LCA> // of two given values n1 and n2> #include> using> namespace> std;> // A Binary Tree node> struct> Node {> > int> key;> > struct> Node *left, *right;> };> // Utility function creates a new binary tree node with> // given key> Node* newNode(> int> k)> {> > Node* temp => new> Node;> > temp->キー = k;>>' k)> (root->right && findPath(root->right, path, k)))>> > return> true> ;> > // If not present in subtree rooted with root, remove> > // root from path[] and return false> > path.pop_back();> > return> false> ;> > // Returns LCA if node n1, n2 are present in the given> // binary tree, otherwise return -1> int> findLCA(Node* root,> int> n1,> int> n2)> > // Driver program to test above functions> int> main()> {> > // Let us create the Binary Tree shown in above diagram.> > Node* root = newNode(1);> > root->left = newNode(2);>> > root->right = newNode(3);>> > root->left->left = newNode(4);>> > root->left->right = newNode(5);>> > root->right->left = newNode(6);>> > root->right->right = newNode(7);>> > cout < <> 'LCA(4, 5) = '> < < findLCA(root, 4, 5);> > cout < <> '
LCA(4, 6) = '> < < findLCA(root, 4, 6);> > cout < <> '
LCA(3, 4) = '> < < findLCA(root, 3, 4);> > cout < <> '
LCA(2, 4) = '> < < findLCA(root, 2, 4);> > return> 0;> }> |
ジャワ
// Java Program for Lowest Common Ancestor> // in a Binary Tree> // A O(n) solution to find LCA of> // two given values n1 and n2> import> java.util.ArrayList;> import> java.util.List;> // A Binary Tree node> class> Node {> > int> data;> > Node left, right;> > Node(> int> value)> > {> > data = value;> > left = right => null> ;> > }> }> public> class> BT_NoParentPtr_Solution1 {> > Node root;> > private> List path1 => new> ArrayList();> > private> List path2 => new> ArrayList();> > // Finds the path from root node to given root of the> > // tree.> > int> findLCA(> int> n1,> int> n2)> > {> > path1.clear();> > path2.clear();> > return> findLCAInternal(root, n1, n2);> > }> > private> int> findLCAInternal(Node root,> int> n1,> int> n2)> > {> > if> (!findPath(root, n1, path1)> > || !findPath(root, n2, path2)) {> > System.out.println((path1.size()>>> 0> )> > ?> 'n1 is present'> > :> 'n1 is missing'> );> > System.out.println((path2.size()>>> 0> )> > ?> 'n2 is present'> > :> 'n2 is missing'> );> > return> -> 1> ;> > }> > int> i;> > for> (i => 0> ; i i++) { // System.out.println(path1.get(i) + ' ' + // path2.get(i)); if (!path1.get(i).equals(path2.get(i))) break; } return path1.get(i - 1); } // Finds the path from root node to given root of the // tree, Stores the path in a vector path[], returns // true if path exists otherwise false private boolean findPath(Node root, int n, List path) { // base case if (root == null) { return false; } // Store this node . The node will be removed if // not in path from root to n. path.add(root.data); if (root.data == n || findPath(root.left, n, path) || findPath(root.right, n, path)) { return true; } // If not present in subtree rooted with root, // remove root from path[] and return false path.remove(path.size() - 1); return false; } // Driver code public static void main(String[] args) { BT_NoParentPtr_Solution1 tree = new BT_NoParentPtr_Solution1(); tree.root = new Node(1); tree.root.left = new Node(2); tree.root.right = new Node(3); tree.root.left.left = new Node(4); tree.root.left.right = new Node(5); tree.root.right.left = new Node(6); tree.root.right.right = new Node(7); System.out.println('LCA(4, 5) = ' + tree.findLCA(4, 5)); System.out.println('LCA(4, 6) = ' + tree.findLCA(4, 6)); System.out.println('LCA(3, 4) = ' + tree.findLCA(3, 4)); System.out.println('LCA(2, 4) = ' + tree.findLCA(2, 4)); } } // This code is contributed by Sreenivasulu Rayanki.> |
Python3
# Python Program for Lowest Common Ancestor in a Binary Tree> # O(n) solution to find LCS of two given values n1 and n2> # A binary tree node> class> Node:> > # Constructor to create a new binary node> > def> __init__(> self> , key):> > self> .key> => key> > self> .left> => None> > self> .right> => None> # Finds the path from root node to given root of the tree.> # Stores the path in a list path[], returns true if path> # exists otherwise false> def> findPath(root, path, k):> > # Baes Case> > if> root> is> None> :> > return> False> > # Store this node is path vector. The node will be> > # removed if not in path from root to k> > path.append(root.key)> > # See if the k is same as root's key> > if> root.key> => => k:> > return> True> > # Check if k is found in left or right sub-tree> > if> ((root.left !> => None> and> findPath(root.left, path, k))> or> > (root.right !> => None> and> findPath(root.right, path, k))):> > return> True> > # If not present in subtree rooted with root, remove> > # root from path and return False> > path.pop()> > return> False> # Returns LCA if node n1 , n2 are present in the given> # binary tree otherwise return -1> def> findLCA(root, n1, n2):> > # To store paths to n1 and n2 fromthe root> > path1> => []> > path2> => []> > # Find paths from root to n1 and root to n2.> > # If either n1 or n2 is not present , return -1> > if> (> not> findPath(root, path1, n1)> or> not> findPath(root, path2, n2)):> > return> -> 1> > # Compare the paths to get the first different value> > i> => 0> > while> (i <> len> (path1)> and> i <> len> (path2)):> > if> path1[i] !> => path2[i]:> > break> > i> +> => 1> > return> path1[i> -> 1> ]> # Driver program to test above function> if> __name__> => => '__main__'> :> > > # Let's create the Binary Tree shown in above diagram> > root> => Node(> 1> )> > root.left> => Node(> 2> )> > root.right> => Node(> 3> )> > root.left.left> => Node(> 4> )> > root.left.right> => Node(> 5> )> > root.right.left> => Node(> 6> )> > root.right.right> => Node(> 7> )> > > print> (> 'LCA(4, 5) = %d'> %> (findLCA(root,> 4> ,> 5> ,)))> > print> (> 'LCA(4, 6) = %d'> %> (findLCA(root,> 4> ,> 6> )))> > print> (> 'LCA(3, 4) = %d'> %> (findLCA(root,> 3> ,> 4> )))> > print> (> 'LCA(2, 4) = %d'> %> (findLCA(root,> 2> ,> 4> )))> # This code is contributed by Nikhil Kumar Singh(nickzuck_007)> |
C#
// C# Program for Lowest Common> // Ancestor in a Binary Tree> // A O(n) solution to find LCA> // of two given values n1 and n2> using> System.Collections;> using> System;> // A Binary Tree node> class> Node {> > public> int> data;> > public> Node left, right;> > public> Node(> int> value)> > {> > data = value;> > left = right => null> ;> > }> }> public> class> BT_NoParentPtr_Solution1 {> > Node root;> > private> ArrayList path1 => new> ArrayList();> > private> ArrayList path2 => new> ArrayList();> > // Finds the path from root> > // node to given root of the> > // tree.> > int> findLCA(> int> n1,> int> n2)> > {> > path1.Clear();> > path2.Clear();> > return> findLCAInternal(root, n1, n2);> > }> > private> int> findLCAInternal(Node root,> int> n1,> int> n2)> > {> > if> (!findPath(root, n1, path1)> > || !findPath(root, n2, path2)) {> > Console.Write((path1.Count>0)>> > :> 'n1 is missing'> );> > Console.Write((path2.Count>0)>> > :> 'n2 is missing'> );> > return> -1;> > }> > int> i;> > for> (i = 0; i i++) { // System.out.println(path1.get(i) // + ' ' + path2.get(i)); if ((int)path1[i] != (int)path2[i]) break; } return (int)path1[i - 1]; } // Finds the path from root node // to given root of the tree, // Stores the path in a vector // path[], returns true if path // exists otherwise false private bool findPath(Node root, int n, ArrayList path) { // base case if (root == null) { return false; } // Store this node . The node // will be removed if not in // path from root to n. path.Add(root.data); if (root.data == n) { return true; } if (root.left != null && findPath(root.left, n, path)) { return true; } if (root.right != null && findPath(root.right, n, path)) { return true; } // If not present in subtree // rooted with root, remove root // from path[] and return false path.RemoveAt(path.Count - 1); return false; } // Driver code public static void Main(String[] args) { BT_NoParentPtr_Solution1 tree = new BT_NoParentPtr_Solution1(); tree.root = new Node(1); tree.root.left = new Node(2); tree.root.right = new Node(3); tree.root.left.left = new Node(4); tree.root.left.right = new Node(5); tree.root.right.left = new Node(6); tree.root.right.right = new Node(7); Console.Write('LCA(4, 5) = ' + tree.findLCA(4, 5)); Console.Write('
LCA(4, 6) = ' + tree.findLCA(4, 6)); Console.Write('
LCA(3, 4) = ' + tree.findLCA(3, 4)); Console.Write('
LCA(2, 4) = ' + tree.findLCA(2, 4)); } } // This code is contributed by Rutvik_56> |
JavaScript
> > // JavaScript Program for Lowest Common> > // Ancestor in a Binary Tree> > // A O(n) solution to find LCA of> > // two given values n1 and n2> > > class Node> > {> > constructor(value) {> > this> .left => null> ;> > this> .right => null> ;> > this> .data = value;> > }> > }> > > let root;> > let path1 = [];> > let path2 = [];> > > // Finds the path from root node to given root of the tree.> > function> findLCA(n1, n2) {> > path1 = [];> > path2 = [];> > return> findLCAInternal(root, n1, n2);> > }> > > function> findLCAInternal(root, n1, n2) {> > > if> (!findPath(root, n1, path1) || !findPath(root, n2, path2))> > {> > document.write((path1.length>0)?>> > 'n1 is present'> :> 'n1 is missing'> );> > document.write((path2.length>0)?>> > 'n2 is present'> :> 'n2 is missing'> );> > return> -1;> > }> > > let i;> > for> (i = 0; i // System.out.println(path1.get(i) + ' ' + path2.get(i)); if (path1[i] != path2[i]) break; } return path1[i-1]; } // Finds the path from root node to // given root of the tree, Stores the // path in a vector path[], returns true // if path exists otherwise false function findPath(root, n, path) { // base case if (root == null) { return false; } // Store this node . The node will be removed if // not in path from root to n. path.push(root.data); if (root.data == n) { return true; } if (root.left != null && findPath(root.left, n, path)) { return true; } if (root.right != null && findPath(root.right, n, path)) { return true; } // If not present in subtree rooted with root, // remove root from // path[] and return false path.pop(); return false; } root = new Node(1); root.left = new Node(2); root.right = new Node(3); root.left.left = new Node(4); root.left.right = new Node(5); root.right.left = new Node(6); root.right.right = new Node(7); document.write('LCA(4, 5) = ' + findLCA(4,5) + ''); document.write('LCA(4, 6) = ' + findLCA(4,6) + ''); document.write('LCA(3, 4) = ' + findLCA(3,4) + ''); document.write('LCA(2, 4) = ' + findLCA(2,4));> |
出力
LCA(4, 5) = 2 LCA(4, 6) = 1 LCA(3, 4) = 1 LCA(2, 4) = 2
時間計算量: の上)。ツリーは 2 回走査され、パス配列が比較されます。
補助スペース: の上)。 path1 と path2 用の追加スペース。
単一走査による二分木内の最下位共通祖先:
考え方は、ルートから始めてツリーをたどることです。指定されたキー (n1 および n2) のいずれかがルートと一致する場合、ルートは LCA になります (両方のキーが存在すると仮定します)。ルートがどのキーとも一致しない場合は、左右のサブツリーに対して再帰処理が行われます。
- 1 つのキーが左側のサブツリーに存在し、もう 1 つのキーが右側のサブツリーに存在するノードが LCA です。
- 両方のキーが左側のサブツリーにある場合、左側のサブツリーにも LCA があります。
- それ以外の場合、LCA は正しいサブツリーにあります。
図:
![]()
5 と 6 の LCA を求める
根 は値 1 のノードを指しています。その値は { 5, 6 } と一致しません。左側のサブツリーと右側のサブツリーでキーを探します。
- 左のサブツリー:
- 新しいルート = { 2 } ≠ 5 または 6、したがって再帰を続けます
- 新しいルート = { 4 }、左右のサブツリーは null です。この呼び出しでは NULL を返します
- New Root = { 5 }、値は 5 と一致するため、値 5 のノードが返されます。
- 値 2 を持つ root の関数呼び出しは値 5 を返します。
- 右サブツリー :
- Root = { 3 } ≠ 5 または 6 したがって、再帰を続けます
- Root = { 6 } = 5 または 6 の場合、値 6 のこのノードを返します。
- Root = { 7 } ≠ 5 または 6、NULL を返します
- したがって、値 3 の root に対する関数呼び出しは、値 6 のノードを返します。
- 値 1 を持つノードの左側のサブツリーと右側のサブツリーは両方とも NULL ではないため、1 が LCA になります。
問題を解決するには、次の手順に従ってください。
- ルートをヘルパー関数に渡し、ルートの値が n1 と n2 のいずれかに一致するかどうかを確認します。
- YES の場合、ルートを返します
- else 左右のサブツリーの再帰呼び出し
- 基本的に、事前順序走査を行い、最初に root->value が n1 または n2 と一致するかどうかを確認します。次に、左右のサブツリーをトラバースします。
- 1 つの NULL 値ともう 1 つの非 NULL 値を返すルートがある場合、そのノードに対応する非 NULL 値を返します。
- 左右のサブツリーの両方で非 NULL 値を返すノードが、最下位共通祖先です。
以下は、上記のアプローチの実装です。
C++
/* C++ Program to find LCA of n1 and n2 using one traversal> > * of Binary Tree */> #include> using> namespace> std;> // A Binary Tree Node> struct> Node {> > struct> Node *left, *right;> > int> key;> };> // Utility function to create a new tree Node> Node* newNode(> int> key)> {> > Node* temp => new> Node;> > temp->キー = キー;>> > temp->左 = 温度->右 = NULL;>> > return> temp;> }> // This function returns pointer to LCA of two given values> // n1 and n2. This function assumes that n1 and n2 are> // present in Binary Tree> struct> Node* findLCA(> struct> Node* root,> int> n1,> int> n2)> > > // Base case> > if> (root == NULL)> > return> NULL;> > // If either n1 or n2 matches with root's key, report> > // the presence by returning root (Note that if a key is> > // ancestor of other, then the ancestor key becomes LCA> > if> (root->キー == n1>>' cout < < '
LCA(4, 6) = ' cout < < '
LCA(3, 4) = ' cout < < '
LCA(2, 4) = ' return 0; } // This code is contributed by Aditya Kumar (adityakumar129)> |
C
// C Program to find LCA of n1 and n2 using one traversalof> // Binary Tree> #include> #include> // A Binary Tree Node> typedef> struct> Node {> > struct> Node *left, *right;> > int> key;> } Node;> // Utility function to create a new tree Node> Node* newNode(> int> key)> {> > Node* temp = (Node*)> malloc> (> sizeof> (Node));> > temp->キー = キー;>> > temp->左 = 温度->右 = NULL;>> > return> temp;> }> // This function returns pointer to LCA of two given values> // n1 and n2. This function assumes that n1 and n2 are> // present in Binary Tree> Node* findLCA(Node* root,> int> n1,> int> n2)> > > // Base case> > if> (root == NULL)> > return> NULL;> > // If either n1 or n2 matches with root's key, report> > // the presence by returning root (Note that if a key is> > // ancestor of other, then the ancestor key becomes LCA> > if> (root->キー == n1>> , findLCA(root, 4, 5)->キー);>> , findLCA(root, 4, 6)->キー);>> , findLCA(root, 3, 4)->キー);>> , findLCA(root, 2, 4)->キー);>> |