二叉树中的最低共同祖先 |设置 2(使用父指针)
给定二叉树中两个节点的值,找到最小的共同祖先( LCA )。可以假设两个节点都存在于树中。
例如,考虑图中的二叉树,10 和 14 的 LCA 为 12,8 和 14 的 LCA 为 8。
令 T 为有根树。两个节点 n1 和 n2 之间的最低共同祖先被定义为 T 中同时具有 n1 和 n2 作为后代的最低节点(我们允许一个节点成为其自身的后代)。来源:维基百科。
我们已经讨论了在集合 1 中找到 LCA 的不同方法。当给定父指针时,找到 LCA 变得容易,因为我们可以使用父指针轻松找到节点的所有祖先。
以下是查找 LCA 的步骤。
- 创建一个空的哈希表。
- 在哈希表中插入 n1 及其所有祖先。
- 检查 n2 或其任何祖先是否存在于哈希表中,如果存在则返回第一个现有祖先。
下面是上述步骤的实现。
C
// C++ program to find lowest common ancestor using parent pointer #include
using namespace std; // A Tree Node struct Node { Node *left, *right, *parent; int key; }; // A utility function to create a new BST node Node *newNode(int item) { Node *temp = new Node; temp->key = item; temp->parent = temp->left = temp->right = NULL; return temp; } /* A utility function to insert a new node with given key in Binary Search Tree */ Node *insert(Node *node, int key) { /* If the tree is empty, return a new node */ if (node == NULL) return newNode(key); /* Otherwise, recur down the tree */ if (key < node->key) { node->left = insert(node->left, key); node->left->parent = node; } else if (key > node->key) { node->right = insert(node->right, key); node->right->parent = node; } /* return the (unchanged) node pointer */ return node; } // To find LCA of nodes n1 and n2 in Binary Tree Node *LCA(Node *n1, Node *n2) { // Creata a map to store ancestors of n1 map ancestors; // Insert n1 and all its ancestors in map while (n1 != NULL) { ancestors[n1] = true; n1 = n1->parent; } // Check if n2 or any of its ancestors is in // map. while (n2 != NULL) { if (ancestors.find(n2) != ancestors.end()) return n2; n2 = n2->parent; } return NULL; } // Driver method to test above functions int main(void) { Node * root = NULL; root = insert(root, 20); root = insert(root, 8); root = insert(root, 22); root = insert(root, 4); root = insert(root, 12); root = insert(root, 10); root = insert(root, 14); Node *n1 = root->left->right->left; Node *n2 = root->left; Node *lca = LCA(n1, n2); printf("LCA of %d and %d is %d \n", n1->key, n2->key, lca->key); return 0; } Java
import java.util.HashMap; import java.util.Map; // Java program to find lowest common ancestor using parent pointer // A tree node class Node { int key; Node left, right, parent; Node(int key) { this.key = key; left = right = parent = null; } } class BinaryTree { Node root, n1, n2, lca; /* A utility function to insert a new node with given key in Binary Search Tree */ Node insert(Node node, int key) { /* If the tree is empty, return a new node */ if (node == null) return new Node(key); /* Otherwise, recur down the tree */ if (key < node.key) { node.left = insert(node.left, key); node.left.parent = node; } else if (key > node.key) { node.right = insert(node.right, key); node.right.parent = node; } /* return the (unchanged) node pointer */ return node; } // To find LCA of nodes n1 and n2 in Binary Tree Node LCA(Node n1, Node n2) { // Creata a map to store ancestors of n1 Map
ancestors = new HashMap (); // Insert n1 and all its ancestors in map while (n1 != null) { ancestors.put(n1, Boolean.TRUE); n1 = n1.parent; } // Check if n2 or any of its ancestors is in // map. while (n2 != null) { if (ancestors.containsKey(n2) != ancestors.isEmpty()) return n2; n2 = n2.parent; } return null; } // Driver method to test above functions public static void main(String[] args) { BinaryTree tree = new BinaryTree(); tree.root = tree.insert(tree.root, 20); tree.root = tree.insert(tree.root, 8); tree.root = tree.insert(tree.root, 22); tree.root = tree.insert(tree.root, 4); tree.root = tree.insert(tree.root, 12); tree.root = tree.insert(tree.root, 10); tree.root = tree.insert(tree.root, 14); tree.n1 = tree.root.left.right.left; tree.n2 = tree.root.left; tree.lca = tree.LCA(tree.n1, tree.n2); System.out.println("LCA of " + tree.n1.key + " and " + tree.n2.key + " is " + tree.lca.key); } } // This code has been contributed by Mayank Jaiswal(mayank_24) C#
// C# program to find lowest common ancestor using parent pointer // A tree node using System; using System.Collections; using System.Collections.Generic; public class Node { public int key; public Node left, right, parent; public Node(int key) { this.key = key; left = right = parent = null; } } class BinaryTree { Node root, n1, n2, lca; /* A utility function to insert a new node with given key in Binary Search Tree */ Node insert(Node node, int key) { /* If the tree is empty, return a new node */ if (node == null) return new Node(key); /* Otherwise, recur down the tree */ if (key < node.key) { node.left = insert(node.left, key); node.left.parent = node; } else if (key > node.key) { node.right = insert(node.right, key); node.right.parent = node; } /* return the (unchanged) node pointer */ return node; } // To find LCA of nodes n1 and n2 in Binary Tree Node LCA(Node n1, Node n2) { // Creata a map to store ancestors of n1 Dictionary
ancestors = new Dictionary (); // Insert n1 and all its ancestors in map while (n1 != null) { ancestors.Add(n1,true); n1 = n1.parent; } // Check if n2 or any of its ancestors is in // map. while (n2 != null) { if (ancestors.ContainsKey(n2)) return n2; n2 = n2.parent; } return null; } // Driver code public static void Main(String []args) { BinaryTree tree = new BinaryTree(); tree.root = tree.insert(tree.root, 20); tree.root = tree.insert(tree.root, 8); tree.root = tree.insert(tree.root, 22); tree.root = tree.insert(tree.root, 4); tree.root = tree.insert(tree.root, 12); tree.root = tree.insert(tree.root, 10); tree.root = tree.insert(tree.root, 14); tree.n1 = tree.root.left.right.left; tree.n2 = tree.root.left; tree.lca = tree.LCA(tree.n1, tree.n2); Console.WriteLine("LCA of " + tree.n1.key + " and " + tree.n2.key + " is " + tree.lca.key); } } // This code is contributed by Arnab Kundu C++
// C++ program to find lowest common ancestor using parent pointer #include
using namespace std; // A Tree Node struct Node { Node *left, *right, *parent; int key; }; // A utility function to create a new BST node Node *newNode(int item) { Node *temp = new Node; temp->key = item; temp->parent = temp->left = temp->right = NULL; return temp; } /* A utility function to insert a new node with given key in Binary Search Tree */ Node *insert(Node *node, int key) { /* If the tree is empty, return a new node */ if (node == NULL) return newNode(key); /* Otherwise, recur down the tree */ if (key < node->key) { node->left = insert(node->left, key); node->left->parent = node; } else if (key > node->key) { node->right = insert(node->right, key); node->right->parent = node; } /* return the (unchanged) node pointer */ return node; } // A utility function to find depth of a node // (distance of it from root) int depth(Node *node) { int d = -1; while (node) { ++d; node = node->parent; } return d; } // To find LCA of nodes n1 and n2 in Binary Tree Node *LCA(Node *n1, Node *n2) { // Find depths of two nodes and differences int d1 = depth(n1), d2 = depth(n2); int diff = d1 - d2; // If n2 is deeper, swap n1 and n2 if (diff < 0) { Node * temp = n1; n1 = n2; n2 = temp; diff = -diff; } // Move n1 up until it reaches the same level as n2 while (diff--) n1 = n1->parent; // Now n1 and n2 are at same levels while (n1 && n2) { if (n1 == n2) return n1; n1 = n1->parent; n2 = n2->parent; } return NULL; } // Driver method to test above functions int main(void) { Node * root = NULL; root = insert(root, 20); root = insert(root, 8); root = insert(root, 22); root = insert(root, 4); root = insert(root, 12); root = insert(root, 10); root = insert(root, 14); Node *n1 = root->left->right->left; Node *n2 = root->right; Node *lca = LCA(n1, n2); printf("LCA of %d and %d is %d \n", n1->key, n2->key, lca->key); return 0; } Java
import java.util.HashMap; import java.util.Map; // Java program to find lowest common ancestor using parent pointer // A tree node class Node { int key; Node left, right, parent; Node(int key) { this.key = key; left = right = parent = null; } } class BinaryTree { Node root, n1, n2, lca; /* A utility function to insert a new node with given key in Binary Search Tree */ Node insert(Node node, int key) { /* If the tree is empty, return a new node */ if (node == null) return new Node(key); /* Otherwise, recur down the tree */ if (key < node.key) { node.left = insert(node.left, key); node.left.parent = node; } else if (key > node.key) { node.right = insert(node.right, key); node.right.parent = node; } /* return the (unchanged) node pointer */ return node; } // A utility function to find depth of a node // (distance of it from root) int depth(Node node) { int d = -1; while (node != null) { ++d; node = node.parent; } return d; } // To find LCA of nodes n1 and n2 in Binary Tree Node LCA(Node n1, Node n2) { // Find depths of two nodes and differences int d1 = depth(n1), d2 = depth(n2); int diff = d1 - d2; // If n2 is deeper, swap n1 and n2 if (diff < 0) { Node temp = n1; n1 = n2; n2 = temp; diff = -diff; } // Move n1 up until it reaches the same level as n2 while (diff-- != 0) n1 = n1.parent; // Now n1 and n2 are at same levels while (n1 != null && n2 != null) { if (n1 == n2) return n1; n1 = n1.parent; n2 = n2.parent; } return null; } // Driver method to test above functions public static void main(String[] args) { BinaryTree tree = new BinaryTree(); tree.root = tree.insert(tree.root, 20); tree.root = tree.insert(tree.root, 8); tree.root = tree.insert(tree.root, 22); tree.root = tree.insert(tree.root, 4); tree.root = tree.insert(tree.root, 12); tree.root = tree.insert(tree.root, 10); tree.root = tree.insert(tree.root, 14); tree.n1 = tree.root.left.right.left; tree.n2 = tree.root.right; tree.lca = tree.LCA(tree.n1, tree.n2); System.out.println("LCA of " + tree.n1.key + " and " + tree.n2.key + " is " + tree.lca.key); } } // This code has been contributed by Mayank Jaiswal(mayank_24)
C#
// C# program to find lowest common // ancestor using parent pointer using System; // A tree node public class Node { public int key; public Node left, right, parent; public Node(int key) { this.key = key; left = right = parent = null; } } class GFG { public Node root, n1, n2, lca; /* A utility function to insert a new node with given key in Binary Search Tree */ public virtual Node insert(Node node, int key) { /* If the tree is empty, return a new node */ if (node == null) { return new Node(key); } /* Otherwise, recur down the tree */ if (key < node.key) { node.left = insert(node.left, key); node.left.parent = node; } else if (key > node.key) { node.right = insert(node.right, key); node.right.parent = node; } /* return the (unchanged) node pointer */ return node; } // A utility function to find depth of a // node (distance of it from root) public virtual int depth(Node node) { int d = -1; while (node != null) { ++d; node = node.parent; } return d; } // To find LCA of nodes n1 and n2 // in Binary Tree public virtual Node LCA(Node n1, Node n2) { // Find depths of two nodes // and differences int d1 = depth(n1), d2 = depth(n2); int diff = d1 - d2; // If n2 is deeper, swap n1 and n2 if (diff < 0) { Node temp = n1; n1 = n2; n2 = temp; diff = -diff; } // Move n1 up until it reaches // the same level as n2 while (diff-- != 0) { n1 = n1.parent; } // Now n1 and n2 are at same levels while (n1 != null && n2 != null) { if (n1 == n2) { return n1; } n1 = n1.parent; n2 = n2.parent; } return null; } // Driver Code public static void Main(string[] args) { GFG tree = new GFG(); tree.root = tree.insert(tree.root, 20); tree.root = tree.insert(tree.root, 8); tree.root = tree.insert(tree.root, 22); tree.root = tree.insert(tree.root, 4); tree.root = tree.insert(tree.root, 12); tree.root = tree.insert(tree.root, 10); tree.root = tree.insert(tree.root, 14); tree.n1 = tree.root.left.right.left; tree.n2 = tree.root.right; tree.lca = tree.LCA(tree.n1, tree.n2); Console.WriteLine("LCA of " + tree.n1.key + " and " + tree.n2.key + " is " + tree.lca.key); } } // This code is contributed by Shrikant13
输出:LCA of 10 and 8 is 8
注意:上述实现使用二叉搜索树的插入来创建二叉树,但 LCA函数适用于任何二叉树(不一定是二叉搜索树)。
时间复杂度: O(h) 其中 h 是二叉树的高度,如果我们使用哈希表来实现解决方案(请注意,上述解决方案使用 map 需要 O(Log h) 时间来插入和查找)。所以上述实现的时间复杂度是 O(h Log h)。辅助空间: O(h)
AO(h) 时间和 O(1) 额外空间解决方案:
上述解决方案需要额外的空间,因为我们需要使用哈希表来存储访问过的祖先。我们可以使用以下事实解决 O(1) 额外空间中的问题:如果两个节点处于同一级别,并且如果我们使用两个节点的父指针向上遍历,则到根的路径中的第一个公共节点是 lca。
这个想法是找到给定节点的深度,并通过深度之间的差异向上移动更深的节点指针。一旦两个节点都达到相同的级别,就向上遍历它们并返回第一个公共节点。感谢 Mysterious Mind 提出这种方法。
C++
// C++ program to find lowest common ancestor using parent pointer #include
using namespace std; // A Tree Node struct Node { Node *left, *right, *parent; int key; }; // A utility function to create a new BST node Node *newNode(int item) { Node *temp = new Node; temp->key = item; temp->parent = temp->left = temp->right = NULL; return temp; } /* A utility function to insert a new node with given key in Binary Search Tree */ Node *insert(Node *node, int key) { /* If the tree is empty, return a new node */ if (node == NULL) return newNode(key); /* Otherwise, recur down the tree */ if (key < node->key) { node->left = insert(node->left, key); node->left->parent = node; } else if (key > node->key) { node->right = insert(node->right, key); node->right->parent = node; } /* return the (unchanged) node pointer */ return node; } // A utility function to find depth of a node // (distance of it from root) int depth(Node *node) { int d = -1; while (node) { ++d; node = node->parent; } return d; } // To find LCA of nodes n1 and n2 in Binary Tree Node *LCA(Node *n1, Node *n2) { // Find depths of two nodes and differences int d1 = depth(n1), d2 = depth(n2); int diff = d1 - d2; // If n2 is deeper, swap n1 and n2 if (diff < 0) { Node * temp = n1; n1 = n2; n2 = temp; diff = -diff; } // Move n1 up until it reaches the same level as n2 while (diff--) n1 = n1->parent; // Now n1 and n2 are at same levels while (n1 && n2) { if (n1 == n2) return n1; n1 = n1->parent; n2 = n2->parent; } return NULL; } // Driver method to test above functions int main(void) { Node * root = NULL; root = insert(root, 20); root = insert(root, 8); root = insert(root, 22); root = insert(root, 4); root = insert(root, 12); root = insert(root, 10); root = insert(root, 14); Node *n1 = root->left->right->left; Node *n2 = root->right; Node *lca = LCA(n1, n2); printf("LCA of %d and %d is %d \n", n1->key, n2->key, lca->key); return 0; } Java
import java.util.HashMap; import java.util.Map; // Java program to find lowest common ancestor using parent pointer // A tree node class Node { int key; Node left, right, parent; Node(int key) { this.key = key; left = right = parent = null; } } class BinaryTree { Node root, n1, n2, lca; /* A utility function to insert a new node with given key in Binary Search Tree */ Node insert(Node node, int key) { /* If the tree is empty, return a new node */ if (node == null) return new Node(key); /* Otherwise, recur down the tree */ if (key < node.key) { node.left = insert(node.left, key); node.left.parent = node; } else if (key > node.key) { node.right = insert(node.right, key); node.right.parent = node; } /* return the (unchanged) node pointer */ return node; } // A utility function to find depth of a node // (distance of it from root) int depth(Node node) { int d = -1; while (node != null) { ++d; node = node.parent; } return d; } // To find LCA of nodes n1 and n2 in Binary Tree Node LCA(Node n1, Node n2) { // Find depths of two nodes and differences int d1 = depth(n1), d2 = depth(n2); int diff = d1 - d2; // If n2 is deeper, swap n1 and n2 if (diff < 0) { Node temp = n1; n1 = n2; n2 = temp; diff = -diff; } // Move n1 up until it reaches the same level as n2 while (diff-- != 0) n1 = n1.parent; // Now n1 and n2 are at same levels while (n1 != null && n2 != null) { if (n1 == n2) return n1; n1 = n1.parent; n2 = n2.parent; } return null; } // Driver method to test above functions public static void main(String[] args) { BinaryTree tree = new BinaryTree(); tree.root = tree.insert(tree.root, 20); tree.root = tree.insert(tree.root, 8); tree.root = tree.insert(tree.root, 22); tree.root = tree.insert(tree.root, 4); tree.root = tree.insert(tree.root, 12); tree.root = tree.insert(tree.root, 10); tree.root = tree.insert(tree.root, 14); tree.n1 = tree.root.left.right.left; tree.n2 = tree.root.right; tree.lca = tree.LCA(tree.n1, tree.n2); System.out.println("LCA of " + tree.n1.key + " and " + tree.n2.key + " is " + tree.lca.key); } } // This code has been contributed by Mayank Jaiswal(mayank_24)
C#
// C# program to find lowest common // ancestor using parent pointer using System; // A tree node public class Node { public int key; public Node left, right, parent; public Node(int key) { this.key = key; left = right = parent = null; } } class GFG { public Node root, n1, n2, lca; /* A utility function to insert a new node with given key in Binary Search Tree */ public virtual Node insert(Node node, int key) { /* If the tree is empty, return a new node */ if (node == null) { return new Node(key); } /* Otherwise, recur down the tree */ if (key < node.key) { node.left = insert(node.left, key); node.left.parent = node; } else if (key > node.key) { node.right = insert(node.right, key); node.right.parent = node; } /* return the (unchanged) node pointer */ return node; } // A utility function to find depth of a // node (distance of it from root) public virtual int depth(Node node) { int d = -1; while (node != null) { ++d; node = node.parent; } return d; } // To find LCA of nodes n1 and n2 // in Binary Tree public virtual Node LCA(Node n1, Node n2) { // Find depths of two nodes // and differences int d1 = depth(n1), d2 = depth(n2); int diff = d1 - d2; // If n2 is deeper, swap n1 and n2 if (diff < 0) { Node temp = n1; n1 = n2; n2 = temp; diff = -diff; } // Move n1 up until it reaches // the same level as n2 while (diff-- != 0) { n1 = n1.parent; } // Now n1 and n2 are at same levels while (n1 != null && n2 != null) { if (n1 == n2) { return n1; } n1 = n1.parent; n2 = n2.parent; } return null; } // Driver Code public static void Main(string[] args) { GFG tree = new GFG(); tree.root = tree.insert(tree.root, 20); tree.root = tree.insert(tree.root, 8); tree.root = tree.insert(tree.root, 22); tree.root = tree.insert(tree.root, 4); tree.root = tree.insert(tree.root, 12); tree.root = tree.insert(tree.root, 10); tree.root = tree.insert(tree.root, 14); tree.n1 = tree.root.left.right.left; tree.n2 = tree.root.right; tree.lca = tree.LCA(tree.n1, tree.n2); Console.WriteLine("LCA of " + tree.n1.key + " and " + tree.n2.key + " is " + tree.lca.key); } } // This code is contributed by Shrikant13
输出 :LCA of 10 and 22 is 20
您可能还想查看以下文章:
二叉树中的最低共同祖先 |设置 1
二叉搜索树中的最低共同祖先。
使用 RMQ 在二叉树中查找 LCA