自己写的:
先建树,然后利用后续非递归遍历求解
#include<iostream>
#include<stack>
using namespace std;
const int maxn = 10010;
typedef struct node {
int n;
node* left;
node* right;
}*tree;
int n, m, pre[maxn], in[maxn];
tree createT(int preS, int preE, int inS, int inE) {
if (preS > preE)return NULL;
tree root = new node;
root->n = pre[preS];
int pos = inS;
for (int i = inS; i <= inE; i++) {
if (in[i] == pre[preS]) {
pos = i;
break;
}
}
int length = pos - inS;
root->left = createT(preS + 1, preS + length, inS, pos - 1);
root->right = createT(preS + length + 1, preE, pos + 1, inE);
return root;
}
int getAns(int u, int v, tree t) {
tree stack[maxn], temp[maxn];
int top = -1, tempTop = -1;
tree p = t, pre = NULL;
while (p != NULL || top != -1) {
while (p != NULL) {
stack[++top] = p;
p = p->left;
}
if (top != -1) {
p = stack[top];
if (p->right != NULL && p->right != pre) {
p = p->right;
}
else {
if ((p->n == u) || (p->n == v)) {
if (tempTop == -1) {
for (int i = 0; i <= top; i++) {
tempTop++;
temp[tempTop] = stack[tempTop];
}
}
else {
int length = (top < tempTop) ? top : tempTop;
for (int i = length; i >= 0; i--) {
if (stack[i]->n == temp[i]->n) {
return stack[i]->n;
}
}
}
}
top--;
pre = p;
p = NULL;
}
}
}
}
int main() {
cin >> m >> n;
for (int i = 0; i < n; i++)cin >> in[i];
for (int i = 0; i < n; i++)cin >> pre[i];
tree t = createT(0, n - 1, 0, n - 1);
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
bool findu = false, findv = false;
for (int j = 0; j < n; j++) {
if (pre[j] == u)findu = true;
if (pre[j] == v)findv = true;
}
if (findu == false && findv == false) {
printf("ERROR: %d and %d are not found.\n", u, v);
continue;
}
if (findu == false) {
printf("ERROR: %d is not found.\n", u);
continue;
}
if (findv == false) {
printf("ERROR: %d is not found.\n", v);
continue;
}
int ans = getAns(u, v, t);
if (u == v) {
printf("%d is an ancestor of %d.\n", u, v);
continue;
}
if (ans != u && ans != v) {
printf("LCA of %d and %d is %d.\n", u, v, ans);
continue;
}
if (ans == u) {
printf("%d is an ancestor of %d.\n", u, v);
continue;
}
if (ans == v) {
printf("%d is an ancestor of %d.\n", v, u);
continue;
}
}
}
看了大佬答案后写的:
PAT 1151 LCA in a Binary Tree(30 分)- 甲级
不需要建树,在中序序列中,如果u和v的位置在当前节点root的位置的左边,则lca在root的左子树中,如果u和v的位置在当前节点root的位置的右边,则lca在root的右子树中,否则,u和v在root两侧,那么root就是lca。
关键在于记录每个节点在中序序列中的位置。
#include<iostream>
#include<map>
using namespace std;
const int maxn = 1010;
int pre[maxn], in[maxn], m, n;
map<int, int>pos;//记录各个节点在中序序列中的位置
void lca(int inS, int inE, int root, int u, int v) {//root是中序序列中[inS,inE]这一部分子树的根
//在先序序列中的位置
if (inS > inE)return;
int rootPos = pos[pre[root]];//求## 标题子树根在中序序列中的位置
int uPos = pos[u];
int vPos = pos[v];
if (uPos < rootPos && vPos < rootPos)
lca(inS, rootPos - 1, root + 1, u, v);
else if (uPos > rootPos&& vPos > rootPos)
lca(rootPos + 1, inE, root + rootPos - inS + 1, u, v);
else if ((uPos<rootPos && vPos>rootPos) || (uPos > rootPos&& vPos < rootPos))
printf("LCA of %d and %d is %d.\n", u, v, pre[root]);
else if (uPos == rootPos)
printf("%d is an ancestor of %d.\n", u, v);
else if (vPos == rootPos) {
printf("%d is an ancestor of %d.\n", v, u);
}
}
int main() {
cin >> m >> n;
for (int i = 1; i <= n; i++) {
cin >> in[i];
pos[in[i]] = i;
}
for (int i = 1; i <= n; i++)cin >> pre[i];
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
if (pos.count(u) == 0 && pos.count(v) == 0)
printf("ERROR: %d and %d are not found.\n", u, v);
else if (pos.count(u) == 0 || pos.count(v) == 0)
printf("ERROR: %d is not found.\n", pos.count(u) == 0 ? u : v);
else
lca(1, n, 1, u, v);
}
return 0;
}
注意:u和v相等且都在树中时,输出格式是:u is an ancestor of u.而不是LCA of u and u is u.这里写错会导致第二个测点不通过
递归求LCA,还是比较容易理解的。
(二叉树)二叉树的最近公共祖先
tree lca(tree root, tree p, tree q) {//这里假设p和q都在树上
if(root==p||root==q||!root)return root;
tree left=lca(root->left, p, q);
tree right=lca(root->right, p, q);
if(!left&&!right)return NULL;//左右子树都没有找到p和q
else if(left&&!right)return left;//。。。
else if(right&&!left)return right; //。。。
else //p和q分属左右子树的情况
return root;
}
我好菜呀