给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。
最近公共祖先是两个节点的公共的祖先节点且具有最大深度。
样例
对于下面这棵二叉树
4
/ \
3 7
/ \
5 6
LCA(3, 5) = 4
LCA(5, 6) = 7
LCA(6, 7) = 7
一、树为二叉查找树
二叉查找树的创建:
//创建二叉搜索树
struct TreeNode
{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(val)
{
this->val = val;
this->left = this->right = NULL;
}
};
//插入
void Treeinsert(TreeNode* &root, int val)
{
TreeNode*node = new TreeNode(val);
if (root == NULL)
{
root->val = val;
return;
}
TreeNode*pre = NULL;
TreeNode*p = root;
while (p)
{
pre = p;
if (val < p->val)
p = p->left;
else
p = p->right;
}
if (val<pre->val)
pre->left=node;
else
pre->right=node;
}
}
思路:
1、二叉搜索树是排过序的,位于左子树的结点都比父节点小,位于右子树的结点都比父节点大。
2、从树的根结点开始和输入的两个结点比较。
如果当前结点比两个结点的值都大,则最低的共同父节点一定在当前结点的左子树中
如果当前结点比两个结点的值都小,则最低共同父节点一定在当前结点的右子树中。
这样,在树中从上到下找到的第一个在两个输入结点值之间的结点即最低公共祖先。
代码:
自己写的代码,非递归
TreeNode* LCA(TreeNode* root, TreeNode*A, TreeNode*B)
{
if (root == NULL)
return NULL;
while (root != NULL)
{
if (root->val < min(A->val,B->val))
root = root->right;
if (root->val > max(A->val,B->val))
root = root->left;
else
return root;
}
return NULL;
}
参考他人的代码:
// 最近公共祖先
TreeNode *LCA(TreeNode *root, TreeNode *u, TreeNode *v) {
// 空树
if (root == NULL || u == NULL || v == NULL) {
return NULL;
}
// u < t < v or v < t < u
if ((u->val < root->val && root->val < v->val) ||
(v->val < root->val && root->val < u->val)) {
return root;
}
// u < root and v < root left sub tree
if (u->val < root->val && v->val < root->val) {
// u是v祖先 or v是u的祖先
if (root->left == u || root->left == v) {
return root;
}/
return LCA(root->left, u, v);
}
// u > root and v > root right sub tree
if (u->val > root->val && v->val > root->val) {
// u是v祖先 or v是u的祖先
if (root->right == u || root->right == v) {
return root;
}
return LCA(root->right, u, v);
}
return NULL;
}
二叉树,但每个结点都有指向父节点的指针next.
思路:分别从给定的两个节点出发上溯到根节点,形成两条相交的链表,问题转化为求这两个相交链表的第一个交点。
即传统方法:求出linkedList A的长度lengthA, linkedList B的长度LengthB。然后让长的那个链表走过abs(lengthA-lengthB)步之后,齐头并进,就能解决了。
代码:
int getlength(TreeNode*node)
{
int length = 0;
TreeNode*temp = node;
while (temp)
{
length++;
temp = temp->next;
}
return length;
}
TreeNode* LCA(TreeNode*node1, TreeNode* node2)
{
int length1 = getlength(node1);
int length2 = getlength(node2);
TreeNode* pt1 = NULL;
TreeNode* pt2 = NULL;
int k = 0;
if (length1 >= length2)
{
TreeNode*temp = node1;
while (k++ < (length1 - length2))
{
temp = temp->next;
}
pt1 = temp;
pt2 = node2;
}
else
if (length1 < length2)
{
TreeNode*temp = node2;
while (k++ < (length2 - length1))
{
temp = temp->next;
}
pt1 = temp;
pt2 = node1;
}
while(pt1&&pt2&&pt1 != pt2)
{
pt1 = pt1->next;
pt2 = pt2->next;
}
return pt1;
普通二叉树:无父节点指针
思路:
记录从根找到node1和node2的路径,然后再把它们的路径用类似的情况一来做分析,比如还是node1=3,node2=8这个case.我们肯定可以从根节点开始找到3这个节点,同时记录下路径3,4,6,10,类似的我们也可以找到8,6,10。我们把这样的信息存储到两个vector里面,把长的vector开始的多余节点3扔掉,从相同剩余长度开始比较,4!=8, 6==6,我们找到了我们的答案。
写的很好,代码:
//找到root到结点n的路径path
bool nodepath(TreeNode*root, TreeNode* value, vector<TreeNode*>&path)
{
if (root == NULL)
return false;
if (root==value)
{
path.push_back(root);
return true;
}
if (nodepath(root->left, value, path))
{
path.push_back(root);
return true;}
else if (nodepath(root->right, value, path))
{
path.push_back(root);
return true;}
else
return false;
}
//LCA函数寻找最近公共祖先
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* A,TreeNode* B)
{
vector<TreeNode*>path1;
vector<TreeNode*>path2;
bool find = false;
find|= nodepath(root, A, path1);
find&= nodepath(root, B, path2);
TreeNode*p = NULL;
if(find)
{
int minsize = path1.size() > path2.size() ? path2.size() : path1.size();
int it1 = path1.size() - minsize;
int it2 = path2.size() - minsize;
for (; it1 < path1.size(), it2 < path2.size(); it1++, it2++)
{
if (path1[it1] == path2[it2])
{
p = path1[it1];
break;
}
}
}
return p;
}
};