给定先序中序遍历的序列,可以确定一颗唯一的树

先序遍历第一个遍历到的是根,中序遍历确定左右子树

查结点a和结点b的最近公共祖先,简单lca思路:

1.如果a和b分别在当前根的左右子树,当前的根就是最近祖先

2.如果根等于a或者根等于b了,根就是最近祖先;判断和a等还是和b等就行了

3.如果都在左子树上,递归查左子树就可以了。这里找到左子树的边界和根(通过先序中序序列)

4.如果都在右子树上,递归查右子树。

代码1:不建树的做法,参考柳婼blog~

#include<bits/stdc++.h>
using namespace std; vector<int> in, pre;
map<int, int > pos; //先序遍历第一个遍历到的是根,中序遍历确定左右子树 //lca 递归之美 parms:中序左边界 中序右边界 先序遍历到的根的下标 ab值
void lca(int inl, int inr, int preRoot, int a, int b) {
if (inl > inr) return;//出错
int inRoot = pos[pre[preRoot]], aIn = pos[a], bIn = pos[b];//取当前根、左边、右边、位置
if (aIn < inRoot && bIn < inRoot) lca(inl, inRoot - 1, preRoot + 1, a, b);//如果a和b都在左子树,递归查找左子树。参数变化(参考中序遍历):左子树边界(inl~inRoot),先序遍历到下一个结点也就是preRoot+1
else if (aIn > inRoot && bIn > inRoot) lca(inRoot + 1, inr, preRoot + 1 + (inRoot - inl), a, b);//如果ab都在右子树,递归查找右子树。参数变化:找到中序右子树的界限preRoot+1~inr,找到右子树的先序遍历的根(当前的preRoot + (中序根-左边界inl) + 1),因为右子树先序遍历总是在最后的,等所有左子树上的结点遍历完了才开始遍历右子树,左子树上结点个数也就是需要加的偏移量
else if ((aIn < inRoot && bIn > inRoot) || (aIn > inRoot && bIn < inRoot)) printf("LCA of %d and %d is %d.\n", a, b, in[inRoot]);//如果ab一左一右,那么根节点就是他们的最近公共祖先
else if (aIn == inRoot)
printf("%d is an ancestor of %d.\n", a, b);//如果a是根,a就是b的祖先
else if (bIn == inRoot)
printf("%d is an ancestor of %d.\n", b, a);//同上
} int main() {
int m, n, a, b;
cin >> m >> n;
in.resize(n + 1), pre.resize(n + 1);
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++) {
cin >> a >> b;
if (pos[a] == 0 && pos[b] == 0) {
printf("ERROR: %d and %d are not found.\n", a, b);
}
else if (pos[a] == 0 || pos[b] == 0) {
printf("ERROR: %d is not found.\n", pos[a] == 0 ? a : b);
}
else {
lca(1, n, 1, a, b);
}
}
return 0;
}

代码2:递归建树,查lca

链表树,lca也不用优化的

查结点a和结点b的最近公共祖先,简单lca思路:

1.如果a和b分别在当前根的左右子树,当前的根就是最近祖先

2.如果根等于a或者根等于b了,根就是最近祖先;判断和a等还是和b等就行了

3.上述条件都不满足的话,就递归查左子树,递归查右子树。

点击查看

另:PAT常考树的前中后遍历问题

后序确定根节点,中序找到根节点的下标后,根节点左边就是左子树、右边就是右子树了。

1.已知后序与中序输出前序---不建树做法

2.PAT 甲级1020 已知后序与中序输出层序---不建树做法(重点在于理清楚左右子树的root、left、right下标)

与上面方法相比下面方法,把当前遍历到的根节点设置为全局变量cur,先遍历右子树、再遍历左子树;

符合后序遍历的遍历步骤(左右根),不需要计算左子树根的下标,所以更简单直观

3.PAT 甲级1020 已知后序与中序输出层序---建树做法 (递归建树的 left和right下标更直观)

4.PAT 甲级1119 已知后序与先序输出中序---搞清楚下标

getIn(preLeft + 1, i - 1, postLeft, postLeft + (i - preLeft - 1) - 1);

getIn(i, preRight, postLeft + (i - preLeft - 1), postRight - 1);

前序的开始的第一个应该是后序的最后一个是相等的,这个结点就是根结点。

以后序的根结点的前面一个结点作为参考,寻找这个结点在前序的位置,就可以根据这个位置来划分左右孩子,递归处理。

重点在于后序的下标确定方法:

左子树区间也就等于:[posleft,posleft + 左子树结点的个数 - 1]

左子树结点个数 就等于 (前序中当前根节点索引的位置 - 左子树前序左边界preleft)

综上 左子树区间就是[posleft,posleft+(前序中当前根节点索引的位置 - 左子树前序左边界preleft) ],

右子树亦同,右子树区间[posleft + 左子树结点的个数 ,postRight - 1]

小结:几道题都需计算清楚 在后序遍历中”根的下标位置“。

PAT甲级|1151 LCA in a Binary Tree 先序中序遍历建树 lca的更多相关文章

  1. 【PAT甲级】1102 Invert a Binary Tree (25 分)(层次遍历和中序遍历)

    题意: 输入一个正整数N(<=10),接着输入0~N-1每个结点的左右儿子结点,输出这颗二叉树的反转的层次遍历和中序遍历. AAAAAccepted code: #define HAVE_STR ...

  2. Leetcode 94. Binary Tree Inorder Traversal (中序遍历二叉树)

    Given a binary tree, return the inorder traversal of its nodes' values. For example: Given binary tr ...

  3. [LeetCode] Binary Tree Inorder Traversal 中序排序

    Given a binary tree, return the inorder traversal of its nodes' values. For example:Given binary tre ...

  4. 094 Binary Tree Inorder Traversal 中序遍历二叉树

    给定一个二叉树,返回其中序遍历.例如:给定二叉树 [1,null,2,3],   1    \     2    /   3返回 [1,3,2].说明: 递归算法很简单,你可以通过迭代算法完成吗?详见 ...

  5. 【PAT甲级】1066 Root of AVL Tree (25 分)(AVL树建树模板)

    题意: 输入一个正整数N(<=20),接着输入N个结点的值,依次插入一颗AVL树,输出最终根结点的值. AAAAAccepted code: #define HAVE_STRUCT_TIMESP ...

  6. 【PAT 甲级】1151 LCA in a Binary Tree (30 分)

    题目描述 The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has bo ...

  7. PAT 甲级 1151 LCA in a Binary Tree

    https://pintia.cn/problem-sets/994805342720868352/problems/1038430130011897856 The lowest common anc ...

  8. PAT 1151 LCA in a Binary Tree[难][二叉树]

    1151 LCA in a Binary Tree (30 分) The lowest common ancestor (LCA) of two nodes U and V in a tree is ...

  9. PAT Advanced 1151 LCA in a Binary Tree (30) [树的遍历,LCA算法]

    题目 The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both ...

随机推荐

  1. 耐人寻味的CSS属性font-family

    font-family是一个网站用户体验的第一入口,非常有必要花功夫来研究一下.我们首先需要了解衬线字体和无衬线字体,接着了解中英文的常用字体及其适用性. 衬线字体 衬线(serif)的笔画有粗有细的 ...

  2. Oracle ASM无法识别扩展分区的磁盘设备

    在linux 环境下,我们一般通过udev或者asmlib来绑定磁盘分区作为ASM的候选存储单元.在使用udev的情况下,一般只要我们可以看到被绑定的磁盘的设备,并且这些设备的属主和权限没有问题,AS ...

  3. Markdown语法教程

    标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 效果如下: 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 段落 换 ...

  4. Centos 7.5私有域名服务器部署(coredns+etcd)

    单机配置: 一.安装etcd:   1.安装 yum install etcd -y   2.启动 systemctl start etcd   3.设置开机启动 systemctl enable e ...

  5. 08-Node.js学习笔记-静态资源访问

    静态资源 服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,例如css,javaScript,image文件 动态资源 相同的请求地址不同的响应资源,这种资源就是动态资源 http://ww ...

  6. 【西北师大-2108Java】第十一次作业成绩汇总

    [西北师大-2108Java]第十一次作业成绩汇总 作业题目 面向对象程序设计(JAVA) 第13周学习指导及要求 实验目的与要求 (1)掌握事件处理的基本原理,理解其用途: (2)掌握AWT事件模型 ...

  7. java之数据结构

    数据结构有什么用? 现实世界的存储,我们使用的工具和建模.每种数据结构有自己的优点和缺点,想想如果Google的数据用的是数组的存储,我们还能方便地查询到所需要的数据吗?而算法,在这么多的数据中如何做 ...

  8. 剑指Offer-40.数组中只出现一次的数字(C++/Java)

    题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 分析: 我们知道,两个相同的数字异或的结果等于0,所以利用这个性质将数组中所有的数字异或,求得的结 ...

  9. 设计模式-工厂模式(Factory)(创建型模式)

    以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Product.h #pragma once class Product { public: ; protected: P ...

  10. 蓝牙spp协议分析

    基本概念 蓝牙串口是基于 SPP 协议(Serial Port Profile),能在蓝牙设备之间创建串口进行数据传输的一种设备. 蓝牙串口的目的是针对如何在两个不同设备(通信的两端)上的应用之间保证 ...