二叉树中的最低共同祖先 |设置 1
给定一棵二叉树(不是二叉搜索树)和两个值 n1 和 n2,编写一个程序来查找最小共同祖先。
以下是维基百科对 LCA 的定义:
令 T 为有根树。两个节点 n1 和 n2 之间的最低共同祖先被定义为 T 中同时具有 n1 和 n2 作为后代的最低节点(我们允许一个节点成为其自身的后代)。
T 中 n1 和 n2 的 LCA 是离根最远的 n1 和 n2 的共享祖先。计算最低共同祖先可能很有用,例如,作为确定树中节点对之间距离的过程的一部分:从 n1 到 n2 的距离可以计算为从根到 n1 的距离,加上距离从根到 n2,减去从根到它们最低共同祖先的距离的两倍。 (来源维基)
我们已经讨论了在二叉搜索树中找到 LCA 的有效解决方案。在二叉搜索树中,使用 BST 属性,我们可以在 O(h) 时间内找到 LCA,其中 h 是树的高度。这种实现在二叉树中是不可能的,因为键二叉树节点不遵循任何顺序。以下是在二叉树中查找 LCA 的不同方法。
方法 1(通过将 root 存储到 n1 并将 root 存储到 n2 路径):
下面是一个简单的 O(n) 算法来找到 n1 和 n2 的 LCA。
1)找到从根到n1的路径并将其存储在向量或数组中。
2)找到从根到 n2 的路径,并将其存储在另一个向量或数组中。
3)遍历两条路径,直到数组中的值相同。返回不匹配之前的公共元素。
以下是上述算法的实现。
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
#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->key = k;
temp->left = temp->right = NULL;
return temp;
}
// 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
bool findPath(Node *root, vector &path, int k)
{
// base case
if (root == NULL) return false;
// Store this node in path vector. The node will be removed if
// not in path from root to k
path.push_back(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 && findPath(root->left, path, 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)
{
// to store paths to n1 and n2 from the root
vector path1, path2;
// Find paths from root to n1 and root to n1. If either n1 or n2
// is not present, return -1
if ( !findPath(root, path1, n1) || !findPath(root, path2, n2))
return -1;
/* Compare the paths to get the first different value */
int i;
for (i = 0; i < path1.size() && i < path2.size() ; i++)
if (path1[i] != path2[i])
break;
return path1[i-1];
}
// 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 << "\nLCA(4, 6) = " << findLCA(root, 4, 6);
cout << "\nLCA(3, 4) = " << findLCA(root, 3, 4);
cout << "\nLCA(2, 4) = " << findLCA(root, 2, 4);
return 0;
}
Java
// 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 < path1.size() && i < path2.size(); 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) {
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.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
# 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 present" :
"n1 is missing");
Console.Write((path2.Count > 0) ?
"n2 is present" :
"n2 is missing");
return -1;
}
int i;
for (i = 0; i < path1.Count &&
i < path2.Count; 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("\nLCA(4, 6): " +
tree.findLCA(4, 6));
Console.Write("\nLCA(3, 4): " +
tree.findLCA(3, 4));
Console.Write("\nLCA(2, 4): " +
tree.findLCA(2, 4));
}
}
// This code is contributed by Rutvik_56
Javascript
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->key = key;
temp->left = temp->right = 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->key == n1 || root->key == n2)
return root;
// Look for keys in left and right subtrees
Node *left_lca = findLCA(root->left, n1, n2);
Node *right_lca = findLCA(root->right, n1, n2);
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca && right_lca) return root;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != NULL)? left_lca: right_lca;
}
// Driver program to test above functions
int main()
{
// Let us create binary tree given in the above example
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)->key;
cout << "\nLCA(4, 6) = " << findLCA(root, 4, 6)->key;
cout << "\nLCA(3, 4) = " << findLCA(root, 3, 4)->key;
cout << "\nLCA(2, 4) = " << findLCA(root, 2, 4)->key;
return 0;
}
Java
//Java implementation to find lowest common ancestor of
// n1 and n2 using one traversal of binary tree
/* Class containing left and right child of current
node and key value*/
class Node
{
int data;
Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree
{
//Root of the Binary Tree
Node root;
Node findLCA(int n1, int n2)
{
return findLCA(root, n1, n2);
}
// 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 node, int n1, int n2)
{
// Base case
if (node == 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 (node.data == n1 || node.data == n2)
return node;
// Look for keys in left and right subtrees
Node left_lca = findLCA(node.left, n1, n2);
Node right_lca = findLCA(node.right, n1, n2);
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca!=null && right_lca!=null)
return node;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
/* Driver program to test above functions */
public static void main(String args[])
{
BinaryTree tree = new BinaryTree();
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).data);
System.out.println("LCA(4, 6) = " +
tree.findLCA(4, 6).data);
System.out.println("LCA(3, 4) = " +
tree.findLCA(3, 4).data);
System.out.println("LCA(2, 4) = " +
tree.findLCA(2, 4).data);
}
}
Python3
# Python program to find LCA of n1 and n2 using one
# traversal of Binary tree
# A binary tree node
class Node:
# Constructor to create a new tree node
def __init__(self, key):
self.key = key
self.left = None
self.right = None
# 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
def findLCA(root, n1, n2):
# Base Case
if root is None:
return None
# 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.key == n1 or root.key == n2:
return root
# Look for keys in left and right subtrees
left_lca = findLCA(root.left, n1, n2)
right_lca = findLCA(root.right, n1, n2)
# If both of the above calls return Non-NULL, then one key
# is present in once subtree and other is present in other,
# So this node is the LCA
if left_lca and right_lca:
return root
# Otherwise check if left subtree or right subtree is LCA
return left_lca if left_lca is not None else right_lca
# Driver program to test above function
# Let us create a binary tree given in the above example
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) = ", findLCA(root, 4, 5).key)
print ("LCA(4,6) = ", findLCA(root, 4, 6).key)
print ("LCA(3,4) = ", findLCA(root, 3, 4).key)
print ("LCA(2,4) = ", findLCA(root, 2, 4).key)
# This code is contributed by Nikhil Kumar Singh(nickzuck_007)
C#
// C# implementation to find lowest common
// ancestor of n1 and n2 using one traversal
// of binary tree
using System;
// Class containing left and right
// child of current node and key value
public class Node
{
public int data;
public Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
class BinaryTree{
// Root of the Binary Tree
Node root;
Node findLCA(int n1, int n2)
{
return findLCA(root, n1, n2);
}
// 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 node, int n1, int n2)
{
// Base case
if (node == 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 (node.data == n1 || node.data == n2)
return node;
// Look for keys in left and right subtrees
Node left_lca = findLCA(node.left, n1, n2);
Node right_lca = findLCA(node.right, n1, n2);
// If both of the above calls return Non-NULL,
// then one key is present in once subtree
// and other is present in other, So this
// node is the LCA
if (left_lca != null && right_lca != null)
return node;
// Otherwise check if left subtree or
// right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
// Driver code
public static void Main(string []args)
{
BinaryTree tree = new BinaryTree();
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.WriteLine("LCA(4, 5) = " +
tree.findLCA(4, 5).data);
Console.WriteLine("LCA(4, 6) = " +
tree.findLCA(4, 6).data);
Console.WriteLine("LCA(3, 4) = " +
tree.findLCA(3, 4).data);
Console.WriteLine("LCA(2, 4) = " +
tree.findLCA(2, 4).data);
}
}
// This code is contributed by pratham76
Javascript
C++
/* C++ program to find LCA of n1 and n2 using one traversal of Binary Tree.
It handles all cases even when n1 or n2 is not there in 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->key = key;
temp->left = temp->right = NULL;
return temp;
}
// This function returns pointer to LCA of two given values n1 and n2.
// v1 is set as true by this function if n1 is found
// v2 is set as true by this function if n2 is found
struct Node *findLCAUtil(struct Node* root, int n1, int n2, bool &v1, bool &v2)
{
// Base case
if (root == NULL) return NULL;
// If either n1 or n2 matches with root's key, report the presence
// by setting v1 or v2 as true and return root (Note that if a key
// is ancestor of other, then the ancestor key becomes LCA)
if (root->key == n1)
{
v1 = true;
return root;
}
if (root->key == n2)
{
v2 = true;
return root;
}
// Look for keys in left and right subtrees
Node *left_lca = findLCAUtil(root->left, n1, n2, v1, v2);
Node *right_lca = findLCAUtil(root->right, n1, n2, v1, v2);
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca && right_lca) return root;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != NULL)? left_lca: right_lca;
}
// Returns true if key k is present in tree rooted with root
bool find(Node *root, int k)
{
// Base Case
if (root == NULL)
return false;
// If key is present at root, or in left subtree or right subtree,
// return true;
if (root->key == k || find(root->left, k) || find(root->right, k))
return true;
// Else return false
return false;
}
// This function returns LCA of n1 and n2 only if both n1 and n2 are present
// in tree, otherwise returns NULL;
Node *findLCA(Node *root, int n1, int n2)
{
// Initialize n1 and n2 as not visited
bool v1 = false, v2 = false;
// Find lca of n1 and n2 using the technique discussed above
Node *lca = findLCAUtil(root, n1, n2, v1, v2);
// Return LCA only if both n1 and n2 are present in tree
if (v1 && v2 || v1 && find(lca, n2) || v2 && find(lca, n1))
return lca;
// Else return NULL
return NULL;
}
// Driver program to test above functions
int main()
{
// Let us create binary tree given in the above example
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);
Node *lca = findLCA(root, 4, 5);
if (lca != NULL)
cout << "LCA(4, 5) = " << lca->key;
else
cout << "Keys are not present ";
lca = findLCA(root, 4, 10);
if (lca != NULL)
cout << "\nLCA(4, 10) = " << lca->key;
else
cout << "\nKeys are not present ";
return 0;
}
Java
// Java implementation to find lowest common ancestor of
// n1 and n2 using one traversal of binary tree
// It also handles cases even when n1 and n2 are not there in Tree
/* Class containing left and right child of current node and key */
class Node
{
int data;
Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree
{
// Root of the Binary Tree
Node root;
static boolean v1 = false, v2 = false;
// This function returns pointer to LCA of two given
// values n1 and n2.
// v1 is set as true by this function if n1 is found
// v2 is set as true by this function if n2 is found
Node findLCAUtil(Node node, int n1, int n2)
{
// Base case
if (node == null)
return null;
//Store result in temp, in case of key match so that we can search for other key also.
Node temp=null;
// If either n1 or n2 matches with root's key, report the presence
// by setting v1 or v2 as true and return root (Note that if a key
// is ancestor of other, then the ancestor key becomes LCA)
if (node.data == n1)
{
v1 = true;
temp = node;
}
if (node.data == n2)
{
v2 = true;
temp = node;
}
// Look for keys in left and right subtrees
Node left_lca = findLCAUtil(node.left, n1, n2);
Node right_lca = findLCAUtil(node.right, n1, n2);
if (temp != null)
return temp;
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca != null && right_lca != null)
return node;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
// Finds lca of n1 and n2 under the subtree rooted with 'node'
Node findLCA(int n1, int n2)
{
// Initialize n1 and n2 as not visited
v1 = false;
v2 = false;
// Find lca of n1 and n2 using the technique discussed above
Node lca = findLCAUtil(root, n1, n2);
// Return LCA only if both n1 and n2 are present in tree
if (v1 && v2)
return lca;
// Else return NULL
return null;
}
/* Driver program to test above functions */
public static void main(String args[])
{
BinaryTree tree = new BinaryTree();
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);
Node lca = tree.findLCA(4, 5);
if (lca != null)
System.out.println("LCA(4, 5) = " + lca.data);
else
System.out.println("Keys are not present");
lca = tree.findLCA(4, 10);
if (lca != null)
System.out.println("LCA(4, 10) = " + lca.data);
else
System.out.println("Keys are not present");
}
}
Python3
""" Program to find LCA of n1 and n2 using one traversal of
Binary tree
It handles all cases even when n1 or n2 is not there in tree
"""
# A binary tree node
class Node:
# Constructor to create a new node
def __init__(self, key):
self.key = key
self.left = None
self.right = None
# This function return pointer to LCA of two given values
# n1 and n2
# v1 is set as true by this function if n1 is found
# v2 is set as true by this function if n2 is found
def findLCAUtil(root, n1, n2, v):
# Base Case
if root is None:
return None
# IF either n1 or n2 matches ith root's key, report
# the presence by setting v1 or v2 as true and return
# root (Note that if a key is ancestor of other, then
# the ancestor key becomes LCA)
if root.key == n1 :
v[0] = True
return root
if root.key == n2:
v[1] = True
return root
# Look for keys in left and right subtree
left_lca = findLCAUtil(root.left, n1, n2, v)
right_lca = findLCAUtil(root.right, n1, n2, v)
# If both of the above calls return Non-NULL, then one key
# is present in once subtree and other is present in other,
# So this node is the LCA
if left_lca and right_lca:
return root
# Otherwise check if left subtree or right subtree is LCA
return left_lca if left_lca is not None else right_lca
def find(root, k):
# Base Case
if root is None:
return False
# If key is present at root, or if left subtree or right
# subtree , return true
if (root.key == k or find(root.left, k) or
find(root.right, k)):
return True
# Else return false
return False
# This function returns LCA of n1 and n2 on value if both
# n1 and n2 are present in tree, otherwise returns None
def findLCA(root, n1, n2):
# Initialize n1 and n2 as not visited
v = [False, False]
# Find lca of n1 and n2 using the technique discussed above
lca = findLCAUtil(root, n1, n2, v)
# Returns LCA only if both n1 and n2 are present in tree
if (v[0] and v[1] or v[0] and find(lca, n2) or v[1] and
find(lca, n1)):
return lca
# Else return None
return None
# Driver program to test above function
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)
lca = findLCA(root, 4, 5)
if lca is not None:
print ("LCA(4, 5) = ", lca.key)
else :
print ("Keys are not present")
lca = findLCA(root, 4, 10)
if lca is not None:
print ("LCA(4,10) = ", lca.key)
else:
print ("Keys are not present")
# This code is contributed by Nikhil Kumar Singh(nickzuck_007)
C#
using System;
// c# implementation to find lowest common ancestor of
// n1 and n2 using one traversal of binary tree
// It also handles cases even when n1 and n2 are not there in Tree
/* Class containing left and right child of current node and key */
public class Node
{
public int data;
public Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree
{
// Root of the Binary Tree
public Node root;
public static bool v1 = false, v2 = false;
// This function returns pointer to LCA of two given
// values n1 and n2.
// v1 is set as true by this function if n1 is found
// v2 is set as true by this function if n2 is found
public virtual Node findLCAUtil(Node node, int n1, int n2)
{
// Base case
if (node == null)
{
return null;
}
//Store result in temp, in case of key match so that we can search for other key also.
Node temp = null;
// If either n1 or n2 matches with root's key, report the presence
// by setting v1 or v2 as true and return root (Note that if a key
// is ancestor of other, then the ancestor key becomes LCA)
if (node.data == n1)
{
v1 = true;
temp = node;
}
if (node.data == n2)
{
v2 = true;
temp = node;
}
// Look for keys in left and right subtrees
Node left_lca = findLCAUtil(node.left, n1, n2);
Node right_lca = findLCAUtil(node.right, n1, n2);
if (temp != null)
{
return temp;
}
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca != null && right_lca != null)
{
return node;
}
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
// Finds lca of n1 and n2 under the subtree rooted with 'node'
public virtual Node findLCA(int n1, int n2)
{
// Initialize n1 and n2 as not visited
v1 = false;
v2 = false;
// Find lca of n1 and n2 using the technique discussed above
Node lca = findLCAUtil(root, n1, n2);
// Return LCA only if both n1 and n2 are present in tree
if (v1 && v2)
{
return lca;
}
// Else return NULL
return null;
}
/* Driver program to test above functions */
public static void Main(string[] args)
{
BinaryTree tree = new BinaryTree();
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);
Node lca = tree.findLCA(4, 5);
if (lca != null)
{
Console.WriteLine("LCA(4, 5) = " + lca.data);
}
else
{
Console.WriteLine("Keys are not present");
}
lca = tree.findLCA(4, 10);
if (lca != null)
{
Console.WriteLine("LCA(4, 10) = " + lca.data);
}
else
{
Console.WriteLine("Keys are not present");
}
}
}
// This code is contributed by Shrikant13
Javascript
输出:
LCA(4, 5) = 2
LCA(4, 6) = 1
LCA(3, 4) = 1
LCA(2, 4) = 2
时间复杂度:上述解决方案的时间复杂度为 O(n)。遍历树两次,然后比较路径数组。
感谢Ravi Chandra Enaganti提出基于此方法的初始解决方案。
方法二(使用单次遍历)
方法 1 在 O(n) 时间内找到 LCA,但需要三个树遍历加上路径数组的额外空间。如果我们假设键 n1 和 n2 存在于二叉树中,我们可以使用二叉树的单次遍历找到 LCA,而无需额外存储路径数组。
这个想法是从根开始遍历树。如果任何给定的键(n1 和 n2)与根匹配,则根是 LCA(假设两个键都存在)。如果根与任何键都不匹配,我们对左子树和右子树进行递归。在其左子树中存在一个键并且在右子树中存在另一个键的节点是 LCA。如果两个键都在左子树中,那么左子树也有 LCA,否则,LCA 在右子树中。
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->key = key;
temp->left = temp->right = 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->key == n1 || root->key == n2)
return root;
// Look for keys in left and right subtrees
Node *left_lca = findLCA(root->left, n1, n2);
Node *right_lca = findLCA(root->right, n1, n2);
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca && right_lca) return root;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != NULL)? left_lca: right_lca;
}
// Driver program to test above functions
int main()
{
// Let us create binary tree given in the above example
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)->key;
cout << "\nLCA(4, 6) = " << findLCA(root, 4, 6)->key;
cout << "\nLCA(3, 4) = " << findLCA(root, 3, 4)->key;
cout << "\nLCA(2, 4) = " << findLCA(root, 2, 4)->key;
return 0;
}
Java
//Java implementation to find lowest common ancestor of
// n1 and n2 using one traversal of binary tree
/* Class containing left and right child of current
node and key value*/
class Node
{
int data;
Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree
{
//Root of the Binary Tree
Node root;
Node findLCA(int n1, int n2)
{
return findLCA(root, n1, n2);
}
// 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 node, int n1, int n2)
{
// Base case
if (node == 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 (node.data == n1 || node.data == n2)
return node;
// Look for keys in left and right subtrees
Node left_lca = findLCA(node.left, n1, n2);
Node right_lca = findLCA(node.right, n1, n2);
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca!=null && right_lca!=null)
return node;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
/* Driver program to test above functions */
public static void main(String args[])
{
BinaryTree tree = new BinaryTree();
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).data);
System.out.println("LCA(4, 6) = " +
tree.findLCA(4, 6).data);
System.out.println("LCA(3, 4) = " +
tree.findLCA(3, 4).data);
System.out.println("LCA(2, 4) = " +
tree.findLCA(2, 4).data);
}
}
Python3
# Python program to find LCA of n1 and n2 using one
# traversal of Binary tree
# A binary tree node
class Node:
# Constructor to create a new tree node
def __init__(self, key):
self.key = key
self.left = None
self.right = None
# 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
def findLCA(root, n1, n2):
# Base Case
if root is None:
return None
# 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.key == n1 or root.key == n2:
return root
# Look for keys in left and right subtrees
left_lca = findLCA(root.left, n1, n2)
right_lca = findLCA(root.right, n1, n2)
# If both of the above calls return Non-NULL, then one key
# is present in once subtree and other is present in other,
# So this node is the LCA
if left_lca and right_lca:
return root
# Otherwise check if left subtree or right subtree is LCA
return left_lca if left_lca is not None else right_lca
# Driver program to test above function
# Let us create a binary tree given in the above example
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) = ", findLCA(root, 4, 5).key)
print ("LCA(4,6) = ", findLCA(root, 4, 6).key)
print ("LCA(3,4) = ", findLCA(root, 3, 4).key)
print ("LCA(2,4) = ", findLCA(root, 2, 4).key)
# This code is contributed by Nikhil Kumar Singh(nickzuck_007)
C#
// C# implementation to find lowest common
// ancestor of n1 and n2 using one traversal
// of binary tree
using System;
// Class containing left and right
// child of current node and key value
public class Node
{
public int data;
public Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
class BinaryTree{
// Root of the Binary Tree
Node root;
Node findLCA(int n1, int n2)
{
return findLCA(root, n1, n2);
}
// 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 node, int n1, int n2)
{
// Base case
if (node == 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 (node.data == n1 || node.data == n2)
return node;
// Look for keys in left and right subtrees
Node left_lca = findLCA(node.left, n1, n2);
Node right_lca = findLCA(node.right, n1, n2);
// If both of the above calls return Non-NULL,
// then one key is present in once subtree
// and other is present in other, So this
// node is the LCA
if (left_lca != null && right_lca != null)
return node;
// Otherwise check if left subtree or
// right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
// Driver code
public static void Main(string []args)
{
BinaryTree tree = new BinaryTree();
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.WriteLine("LCA(4, 5) = " +
tree.findLCA(4, 5).data);
Console.WriteLine("LCA(4, 6) = " +
tree.findLCA(4, 6).data);
Console.WriteLine("LCA(3, 4) = " +
tree.findLCA(3, 4).data);
Console.WriteLine("LCA(2, 4) = " +
tree.findLCA(2, 4).data);
}
}
// This code is contributed by pratham76
Javascript
输出:
LCA(4, 5) = 2
LCA(4, 6) = 1
LCA(3, 4) = 1
LCA(2, 4) = 2
感谢Atul Singh提出这个解决方案。
时间复杂度:上述解决方案的时间复杂度为 O(n),因为该方法以自下而上的方式进行简单的树遍历。
请注意,上述方法假设密钥存在于二叉树中。如果一个键存在而另一个不存在,则它将当前键作为 LCA 返回(理想情况下应该返回 NULL)。
我们可以扩展此方法以处理绕过两个布尔变量 v1 和 v2 的所有情况。当 n1 存在于树中时 v1 设置为真,如果树中存在 n2 则 v2 设置为真。
C++
/* C++ program to find LCA of n1 and n2 using one traversal of Binary Tree.
It handles all cases even when n1 or n2 is not there in 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->key = key;
temp->left = temp->right = NULL;
return temp;
}
// This function returns pointer to LCA of two given values n1 and n2.
// v1 is set as true by this function if n1 is found
// v2 is set as true by this function if n2 is found
struct Node *findLCAUtil(struct Node* root, int n1, int n2, bool &v1, bool &v2)
{
// Base case
if (root == NULL) return NULL;
// If either n1 or n2 matches with root's key, report the presence
// by setting v1 or v2 as true and return root (Note that if a key
// is ancestor of other, then the ancestor key becomes LCA)
if (root->key == n1)
{
v1 = true;
return root;
}
if (root->key == n2)
{
v2 = true;
return root;
}
// Look for keys in left and right subtrees
Node *left_lca = findLCAUtil(root->left, n1, n2, v1, v2);
Node *right_lca = findLCAUtil(root->right, n1, n2, v1, v2);
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca && right_lca) return root;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != NULL)? left_lca: right_lca;
}
// Returns true if key k is present in tree rooted with root
bool find(Node *root, int k)
{
// Base Case
if (root == NULL)
return false;
// If key is present at root, or in left subtree or right subtree,
// return true;
if (root->key == k || find(root->left, k) || find(root->right, k))
return true;
// Else return false
return false;
}
// This function returns LCA of n1 and n2 only if both n1 and n2 are present
// in tree, otherwise returns NULL;
Node *findLCA(Node *root, int n1, int n2)
{
// Initialize n1 and n2 as not visited
bool v1 = false, v2 = false;
// Find lca of n1 and n2 using the technique discussed above
Node *lca = findLCAUtil(root, n1, n2, v1, v2);
// Return LCA only if both n1 and n2 are present in tree
if (v1 && v2 || v1 && find(lca, n2) || v2 && find(lca, n1))
return lca;
// Else return NULL
return NULL;
}
// Driver program to test above functions
int main()
{
// Let us create binary tree given in the above example
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);
Node *lca = findLCA(root, 4, 5);
if (lca != NULL)
cout << "LCA(4, 5) = " << lca->key;
else
cout << "Keys are not present ";
lca = findLCA(root, 4, 10);
if (lca != NULL)
cout << "\nLCA(4, 10) = " << lca->key;
else
cout << "\nKeys are not present ";
return 0;
}
Java
// Java implementation to find lowest common ancestor of
// n1 and n2 using one traversal of binary tree
// It also handles cases even when n1 and n2 are not there in Tree
/* Class containing left and right child of current node and key */
class Node
{
int data;
Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree
{
// Root of the Binary Tree
Node root;
static boolean v1 = false, v2 = false;
// This function returns pointer to LCA of two given
// values n1 and n2.
// v1 is set as true by this function if n1 is found
// v2 is set as true by this function if n2 is found
Node findLCAUtil(Node node, int n1, int n2)
{
// Base case
if (node == null)
return null;
//Store result in temp, in case of key match so that we can search for other key also.
Node temp=null;
// If either n1 or n2 matches with root's key, report the presence
// by setting v1 or v2 as true and return root (Note that if a key
// is ancestor of other, then the ancestor key becomes LCA)
if (node.data == n1)
{
v1 = true;
temp = node;
}
if (node.data == n2)
{
v2 = true;
temp = node;
}
// Look for keys in left and right subtrees
Node left_lca = findLCAUtil(node.left, n1, n2);
Node right_lca = findLCAUtil(node.right, n1, n2);
if (temp != null)
return temp;
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca != null && right_lca != null)
return node;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
// Finds lca of n1 and n2 under the subtree rooted with 'node'
Node findLCA(int n1, int n2)
{
// Initialize n1 and n2 as not visited
v1 = false;
v2 = false;
// Find lca of n1 and n2 using the technique discussed above
Node lca = findLCAUtil(root, n1, n2);
// Return LCA only if both n1 and n2 are present in tree
if (v1 && v2)
return lca;
// Else return NULL
return null;
}
/* Driver program to test above functions */
public static void main(String args[])
{
BinaryTree tree = new BinaryTree();
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);
Node lca = tree.findLCA(4, 5);
if (lca != null)
System.out.println("LCA(4, 5) = " + lca.data);
else
System.out.println("Keys are not present");
lca = tree.findLCA(4, 10);
if (lca != null)
System.out.println("LCA(4, 10) = " + lca.data);
else
System.out.println("Keys are not present");
}
}
Python3
""" Program to find LCA of n1 and n2 using one traversal of
Binary tree
It handles all cases even when n1 or n2 is not there in tree
"""
# A binary tree node
class Node:
# Constructor to create a new node
def __init__(self, key):
self.key = key
self.left = None
self.right = None
# This function return pointer to LCA of two given values
# n1 and n2
# v1 is set as true by this function if n1 is found
# v2 is set as true by this function if n2 is found
def findLCAUtil(root, n1, n2, v):
# Base Case
if root is None:
return None
# IF either n1 or n2 matches ith root's key, report
# the presence by setting v1 or v2 as true and return
# root (Note that if a key is ancestor of other, then
# the ancestor key becomes LCA)
if root.key == n1 :
v[0] = True
return root
if root.key == n2:
v[1] = True
return root
# Look for keys in left and right subtree
left_lca = findLCAUtil(root.left, n1, n2, v)
right_lca = findLCAUtil(root.right, n1, n2, v)
# If both of the above calls return Non-NULL, then one key
# is present in once subtree and other is present in other,
# So this node is the LCA
if left_lca and right_lca:
return root
# Otherwise check if left subtree or right subtree is LCA
return left_lca if left_lca is not None else right_lca
def find(root, k):
# Base Case
if root is None:
return False
# If key is present at root, or if left subtree or right
# subtree , return true
if (root.key == k or find(root.left, k) or
find(root.right, k)):
return True
# Else return false
return False
# This function returns LCA of n1 and n2 on value if both
# n1 and n2 are present in tree, otherwise returns None
def findLCA(root, n1, n2):
# Initialize n1 and n2 as not visited
v = [False, False]
# Find lca of n1 and n2 using the technique discussed above
lca = findLCAUtil(root, n1, n2, v)
# Returns LCA only if both n1 and n2 are present in tree
if (v[0] and v[1] or v[0] and find(lca, n2) or v[1] and
find(lca, n1)):
return lca
# Else return None
return None
# Driver program to test above function
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)
lca = findLCA(root, 4, 5)
if lca is not None:
print ("LCA(4, 5) = ", lca.key)
else :
print ("Keys are not present")
lca = findLCA(root, 4, 10)
if lca is not None:
print ("LCA(4,10) = ", lca.key)
else:
print ("Keys are not present")
# This code is contributed by Nikhil Kumar Singh(nickzuck_007)
C#
using System;
// c# implementation to find lowest common ancestor of
// n1 and n2 using one traversal of binary tree
// It also handles cases even when n1 and n2 are not there in Tree
/* Class containing left and right child of current node and key */
public class Node
{
public int data;
public Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree
{
// Root of the Binary Tree
public Node root;
public static bool v1 = false, v2 = false;
// This function returns pointer to LCA of two given
// values n1 and n2.
// v1 is set as true by this function if n1 is found
// v2 is set as true by this function if n2 is found
public virtual Node findLCAUtil(Node node, int n1, int n2)
{
// Base case
if (node == null)
{
return null;
}
//Store result in temp, in case of key match so that we can search for other key also.
Node temp = null;
// If either n1 or n2 matches with root's key, report the presence
// by setting v1 or v2 as true and return root (Note that if a key
// is ancestor of other, then the ancestor key becomes LCA)
if (node.data == n1)
{
v1 = true;
temp = node;
}
if (node.data == n2)
{
v2 = true;
temp = node;
}
// Look for keys in left and right subtrees
Node left_lca = findLCAUtil(node.left, n1, n2);
Node right_lca = findLCAUtil(node.right, n1, n2);
if (temp != null)
{
return temp;
}
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca != null && right_lca != null)
{
return node;
}
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != null) ? left_lca : right_lca;
}
// Finds lca of n1 and n2 under the subtree rooted with 'node'
public virtual Node findLCA(int n1, int n2)
{
// Initialize n1 and n2 as not visited
v1 = false;
v2 = false;
// Find lca of n1 and n2 using the technique discussed above
Node lca = findLCAUtil(root, n1, n2);
// Return LCA only if both n1 and n2 are present in tree
if (v1 && v2)
{
return lca;
}
// Else return NULL
return null;
}
/* Driver program to test above functions */
public static void Main(string[] args)
{
BinaryTree tree = new BinaryTree();
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);
Node lca = tree.findLCA(4, 5);
if (lca != null)
{
Console.WriteLine("LCA(4, 5) = " + lca.data);
}
else
{
Console.WriteLine("Keys are not present");
}
lca = tree.findLCA(4, 10);
if (lca != null)
{
Console.WriteLine("LCA(4, 10) = " + lca.data);
}
else
{
Console.WriteLine("Keys are not present");
}
}
}
// This code is contributed by Shrikant13
Javascript
输出:
LCA(4, 5) = 2
Keys are not present
感谢 Dhruv 提出这个扩展解决方案。
您可能还想查看以下文章:
使用父指针的 LCA
二叉搜索树中的最低共同祖先。