刚开始看到这道题时想到的是先建树,建树的过程中将“孩子-父亲”存入map,然后判断两个节点的公共祖先(需要求树高)。
后来看了《剑指offer》上的题目,想到了一种可以直接在建树的过程中寻找到公共祖先的方法。但是仅适用于查找一次公共祖先的情况。
针对于这道题,由于前序中序序列可以唯一确定一个二叉树,所以不需要建树。使用map保存下”节点值-中序序列中的位置“。在递归过程中:
- 如果u和v在当前节点的两侧,则当前节点就是公共祖先节点。
- 如果当前节点是u或者v,则当前节点就是公共祖先节点。
- 若u和v在当前节点的某一侧,则继续递归u和v所在的部分。

c++代码如下:
#include <bits/stdc++.h>
using namespace std;
int u, v;
map<int, int> ma;
void lca(int *preorder, int *inorder, int len) {
if (len <= 0) return;
int root = ma[preorder[0]];
int loca1 = ma[u];
int loca2 = ma[v];
if ((loca1 < root && root < loca2) || (loca2 < root && root < loca1)) {
cout << "LCA of " << u << " and " << v << " is " << preorder[0] << "." << endl;
return;
}
if (preorder[0] == u || preorder[0] == v) {
if (preorder[0] == u) {
cout << u << " is an ancestor of " << v << "." << endl;
} else {
cout << v << " is an ancestor of " << u << "." << endl;
}
return;
}
if (loca1 < root) {
lca(preorder + 1, inorder, root);
} else {
lca(preorder + root + 1, inorder + root + 1, len - root - 1);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int m, n;
cin >> m >> n;
int inorder[10005], preorder[10005];
for (int i = 0; i < n; i++) {
cin >> inorder[i];
ma.insert(pair<int, int>(inorder[i], i));
}
for (int i = 0; i < n; i++) {
cin >> preorder[i];
}
for (int i = 0; i < m; i++) {
cin >> u >> v;
if (!ma.count(u) && !ma.count(v)) {
cout << "ERROR: " << u << " and " << v << " are not found." << endl;
} else if (!ma.count(u)) {
cout << "ERROR: " << u << " is not found." << endl;
} else if (!ma.count(v)) {
cout << "ERROR: " << v << " is not found." << endl;
} else {
lca(preorder, inorder, n);
}
}
return 0;
}
/*
6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99
3 6
4 2 5 1 3 6
1 2 4 5 3 6
5 6
5 2
5 7
*/
附上建树的过程中寻找到公共祖先的方法:
#include <bits/stdc++.h>
using namespace std;
struct BinaryTreeNode {
int m_nValue;
BinaryTreeNode *m_pLeft;
BinaryTreeNode *m_pRight;
BinaryTreeNode(int m_nValue) {
this->m_nValue = m_nValue;
this->m_pLeft = NULL;
this->m_pRight = NULL;
}
};
int u = 5, v = 6;
BinaryTreeNode *lca(const int *preorder, const int *inorder, int len) {
if (len <= 0)
return NULL;
BinaryTreeNode *node = new BinaryTreeNode(preorder[0]);
if (node->m_nValue == u || node->m_nValue == v)
return node;
int dis = find(inorder, inorder + len, node->m_nValue) - inorder;
node->m_pLeft = lca(preorder + 1, inorder, dis);
node->m_pRight = lca(preorder + 1 + dis, inorder + 1 + dis, len - dis - 1);
if (node->m_pLeft != NULL && node->m_pRight != NULL)
return node;
return node->m_pLeft ? node->m_pLeft : node->m_pRight;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int preorder[] = {1, 2, 4, 5, 3, 6};
int inorder[] = {4, 2, 5, 1, 3, 6};
BinaryTreeNode *ancestor = lca(preorder, inorder, 6);
cout << ancestor->m_nValue << endl;
return 0;
}
本文介绍了一种在二叉树中寻找两个节点的最近公共祖先的有效算法,通过利用前序和中序遍历序列,避免了树的构建过程,直接在递归中判断并返回公共祖先节点。

9029

被折叠的 条评论
为什么被折叠?



