题目链接在此
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
_______6______ / \ ___2__ ___8__ / \ / \ 0 _4 7 9 / \ 3 5
For example, the lowest common ancestor (LCA) of nodes 2
and 8
is 6
. Another example is LCA of nodes 2
and 4
is 2
, since a node can be a descendant of itself according to the LCA definition.
应该也是比较经典和常见的一道题了。
【注】看样子应该是假定总root和n1、n2若非NULL,则n1、n2一定在总root这棵树中能够找到。
这道题里是二叉查找树,树的节点有明显的特征,即排列和大小顺序有关,那么首先就可以利用这一点来做:
如果n1,n2比root小, 则LCA一定在左子树; 如果n1,n2比root大, 则LCA一定在右子树。如果一大一小,则LCA一定就是root。
class Solution {
public:
TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *n1, TreeNode *n2){
if (root == NULL || n1 == NULL || n2 == NULL)
return NULL;
if (n1->val < root->val && n2->val < root->val) {
return lowestCommonAncestor(root->left, n1, n2);
}
else if (n1->val > root->val && n2->val > root->val) {
return lowestCommonAncestor(root->right, n1, n2);
}
else
return root;
}
};
那么一般的二叉树该怎样找呢?
比较直观的方法是自顶向下:记录下总root到n1、n2的路径,比较两条路径最晚出现的公共节点。
那么,自底向上应该怎样做呢?
在这篇文章中给出了方法:
A Bottom-up Approach (Worst case O(n) ):
Using a bottom-up approach, we can improve over the top-down approach by avoiding traversing the same nodes over and over again.
We traverse from the bottom, and once we reach a node which matches one of the two nodes, we pass it up to its parent. The parent would then test its left and right subtree if each contain one of the two nodes. If yes, then the parent must be the LCA and we pass its parent up to the root. If not, we pass the lower node which contains either one of the two nodes (if the left or right subtree contains either p or q), or NULL (if both the left and right subtree does not contain either p or q) up.
Sounds complicated? Surprisingly the code appears to be much simpler than the top-down one.
以下为源代码(注释来自这位大神):
class Solution{
public:
TreeNode *LowestCommonAncestor(TreeNode *root, TreeNode *n1, TreeNode *n2){
//如果当前根结点为空返回NULL
if (root == NULL){
return NULL;
}
//若当前找到n1或者n2其中一个,则直接返回
if (root == n1 || root == n2){
return root;
}
//分别从左右子树中查找n1和n2
TreeNode *left = LowestCommonAncestor(root->left, n1, n2);
TreeNode *right = LowestCommonAncestor(root->right, n1, n2);
//若正好在分别在左右子树中找到n1和n2则说明当前节点就是要找的解
if (left&&right){
return root;
}
//存在三种情况使得函数在此处返回:
//1.首次在左或右子树中找到n1、n2中的某个节点
//2.从在当前节点的左右子树中已经查找到要找的解
//3.以当前节点为根的子树根本就不存在n1和n2
return left ? left : right;
}
};