刚开始看到这道题时想到的是先建树,建树的过程中将“孩子-父亲”存入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;
}