当前位置: 首页 > 编程日记 > 正文

1151 LCA in a Binary Tree (含求LCA的通法)

目录

解法一思路

结果

解法一改进

解法一改进结果

​解法二思路

解法一代码

解法一改进代码

解法二代码(AC)

解法一思路

1. 根据先序和中序建树

2. 对树进行深度优先遍历,找到每一个结点的父节点(注意:由于值的范围是int,直接用可能导致溢出,所以采用值在中序/先序中的下标来映射)

3. 对于读入的值,先判断有没有出现过,如果都出现过,分别得到两个结点的祖先序列(顺序是从自身到根节点),然后进行双循环比对。最后将得到的结点分别和两个输入值比较来输出结果。

结果

最后两个用例超时

解法一改进

我觉得运行超时是因为最后的双循环复杂度高了再加外层循环,试图加入一个哈希,把双循环变成单循环。

主要改动如下

		int anc;		for(int i = pre[v1].size()-1;i>=0;i--){anc = pre[v1][i];if(preMp[inPos[v2]][inPos[anc]] == 1)break;}

解法一改进结果

 解法二思路

参考了这篇博客 外链 给出的求解LCA的通法,终于AC了。

1. 在结点结构体中加入父节点属性

struct Node{int v;Node *lchild,*rchild,*pa;
};

2. 封装求系谱(包含自身)长度的函数

int getLinkLen(Node* childNode){int ll = 1;while(childNode->pa){childNode = childNode->pa;ll ++;}return ll; 
}

3. 求最近祖先节点的函数

3.1 分别求出结点p和q系谱链的长度

3.2 把更长的一方缩短到和另一方一样长(也许此时两个点已经重合)

3.3 两方同时回溯,直到遇到相同祖先

Node* getLCA(Node* p,Node* q){int pLen = getLinkLen(p);int qLen = getLinkLen(q);while(pLen<qLen){q = q->pa;qLen --;}while(qLen<pLen){p = p->pa;pLen --;}while(p!=q){p = p->pa;q = q->pa;}return p;
}

4. 在建树的过程中新增

4.1 给每个非空结点指明父节点

4.2 由于题目的输入是数值,而getLCA的参数是Node*类型,所以要有int->Node*的映射。

4.3 由于题目的输出是数值,而getLCA的返回值是Node*类型,所以要有Node*->int的映射。

Node* create(int inL,int inR,int preL,int preR){if(preL>preR)return NULL;Node* root = new Node;root->v = preSq[preL];vmp[root] = root->v;nmp[root->v] = root;int k;for(k=inL;k<=inR;k++){if(inSq[k]==root->v)break;}int leftnum = k-inL;root->lchild = create(inL,k-1,preL+1,preL+leftnum);if(root->lchild)root->lchild->pa = root;root->rchild = create(k+1,inR,preL+leftnum+1,preR);if(root->rchild)root->rchild->pa = root;return root;
}

解法一代码

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<map>
#include<vector>
#include<set>using namespace std;const int maxn = 10001;
const int SUP = 2000000000;int inSq[maxn],preSq[maxn];//set<int> st;
map<int,int> appmp;map<int,int> vToIdx;int pre[maxn];//下标为inIdx vector<int> vi,vi1,vi2;struct Node{int v;Node *lchild,*rchild;
}; void getAncest(int idx){while(pre[idx]!=idx){vi.push_back(inSq[idx]);idx = pre[idx];}return;
}Node* create(int inL,int inR,int preL,int preR){if(preL>preR)return NULL;Node* root = new Node;root->v = preSq[preL];int k;for(k=inL;k<=inR;k++){if(inSq[k]==root->v)break;}int leftnum = k-inL;root->lchild = create(inL,k-1,preL+1,preL+leftnum);root->rchild = create(k+1,inR,preL+leftnum+1,preR);return root;
}void DFS(Node* root){if(root==NULL)return;if(root->lchild!=NULL){int sonIdx = vToIdx[root->lchild->v];pre[sonIdx]= vToIdx[root->v];DFS(root->lchild);}if(root->rchild!=NULL){int sonIdx = vToIdx[root->rchild->v];pre[sonIdx]= vToIdx[root->v];DFS(root->rchild);}return;
}int main(){int pair,n;cin>>pair>>n;for(int i=0;i<n;i++){cin>>inSq[i];appmp[inSq[i]] = 1;vToIdx[inSq[i]] = i;}for(int i=0;i<n;i++){cin>>preSq[i];}Node* root = create(0,n-1,0,n-1);int ridx = vToIdx[root->v];pre[ridx] = ridx;DFS(root);while(pair--){int v1,v2;cin>>v1>>v2;if(appmp[v1]==0){if(appmp[v2]==0){printf("ERROR: %d and %d are not found.\n",v1,v2);continue;}else{printf("ERROR: %d is not found.\n",v1);continue;}}else{if(appmp[v2]==0){printf("ERROR: %d is not found.\n",v2);continue;}}vi.clear(); getAncest(vToIdx[v1]);vi1 = vi;vi1.push_back(root->v);vi.clear();getAncest(vToIdx[v2]);vi2 = vi;vi2.push_back(root->v);	bool gotit = false;int LCA;for(int i=0;i<vi1.size()&&gotit==false;i++){for(int j=0;j<vi2.size();j++){if(vi1[i]==vi2[j]){LCA = vi1[i];gotit = true;break;}}}if(LCA==v1){printf("%d is an ancestor of %d.\n",v1,v2);}else if(LCA==v2){printf("%d is an ancestor of %d.\n",v2,v1);}else{printf("LCA of %d and %d is %d.\n",v1,v2,LCA);}}return 0;
}

解法一改进代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
#include<stdlib.h>
#include<time.h>
#include<vector>
#include<set>
#include<string>using namespace std;
typedef long long LL;const int maxn = 10007;
const int MOD = 1000000007;
const int INF = 1000000000;//INF:下确界  
const LL SUP = (1LL<<63)-1;//SUP:上确界 
const double eps = 1e-5;int inSq[maxn],preSq[maxn];
int inPos[maxn];
int n;map<int,int> eximp;map<int,vector<int> > pre;map<int,map<int,int> > preMp;struct Node{int v;Node *lchild,*rchild;
};Node* create(int inL,int inR,int preL,int preR){if(preL>preR)return NULL;Node* root = new Node;root->v = preSq[preL];int k;for(k=inL;k<=inR;k++){if(inSq[k]==root->v)break;}int leftnum = k-inL;root->lchild = create(inL,k-1,preL+1,preL+leftnum);root->rchild = create(k+1,inR,preL+leftnum+1,preR);return root;
}void DFS(Node* root){if(root==NULL)return;pre[root->v].push_back(root->v);preMp[inPos[root->v]][inPos[root->v]] = 1;if(root->lchild!=NULL){pre[root->lchild->v] = pre[root->v];preMp[inPos[root->lchild->v]] = preMp[inPos[root->v]];DFS(root->lchild);}if(root->rchild!=NULL){pre[root->rchild->v] = pre[root->v];preMp[inPos[root->rchild->v]] = preMp[inPos[root->v]];DFS(root->rchild);}
}int main(){int pNum;cin>>pNum>>n;for(int i=0;i<n;i++){cin>>inSq[i];eximp[inSq[i]] = 1;inPos[inSq[i]] = i;}for(int i=0;i<n;i++){cin>>preSq[i];}Node* root = create(0,n-1,0,n-1);DFS(root);while(pNum--){int v1,v2;cin>>v1>>v2;if(eximp[v1]==0||eximp[v2]==0){if(eximp[v1]==1)printf("ERROR: %d is not found.\n",v2);else if(eximp[v2]==1)printf("ERROR: %d is not found.\n",v1);else printf("ERROR: %d and %d are not found.\n",v1,v2);continue;}int anc;		for(int i = pre[v1].size()-1;i>=0;i--){anc = pre[v1][i];if(preMp[inPos[v2]][inPos[anc]] == 1)break;}if(anc==v1||anc==v2){printf("%d is an ancestor of %d.\n",anc==v1?v1:v2,anc==v1?v2:v1);}else  printf("LCA of %d and %d is %d.\n",v1,v2,anc);}return 0;
}

解法二代码(AC)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
#include<stdlib.h>
#include<time.h>
#include<vector>
#include<set>
#include<string>using namespace std;
typedef long long LL;const int maxn = 10007;
const int MOD = 1000000007;
const int INF = 1000000000;//INF:下确界  
const LL SUP = (1LL<<63)-1;//SUP:上确界 
const double eps = 1e-5;int inSq[maxn],preSq[maxn];
int n;map<int,int> eximp;struct Node{int v;Node *lchild,*rchild,*pa;
};map<Node*,int> vmp;
map<int,Node*> nmp;Node* create(int inL,int inR,int preL,int preR){if(preL>preR)return NULL;Node* root = new Node;root->v = preSq[preL];vmp[root] = root->v;nmp[root->v] = root;int k;for(k=inL;k<=inR;k++){if(inSq[k]==root->v)break;}int leftnum = k-inL;root->lchild = create(inL,k-1,preL+1,preL+leftnum);if(root->lchild)root->lchild->pa = root;root->rchild = create(k+1,inR,preL+leftnum+1,preR);if(root->rchild)root->rchild->pa = root;return root;
}int getLinkLen(Node* childNode){int ll = 1;while(childNode->pa){childNode = childNode->pa;ll ++;}return ll; 
} Node* getLCA(Node* p,Node* q){int pLen = getLinkLen(p);int qLen = getLinkLen(q);while(pLen<qLen){q = q->pa;qLen --;}while(qLen<pLen){p = p->pa;pLen --;}while(p!=q){p = p->pa;q = q->pa;}return p;
}int main(){int pNum;cin>>pNum>>n;for(int i=0;i<n;i++){cin>>inSq[i];eximp[inSq[i]] = 1;}for(int i=0;i<n;i++){cin>>preSq[i];}Node* root = create(0,n-1,0,n-1);while(pNum--){int v1,v2;cin>>v1>>v2;if(eximp[v1]==0||eximp[v2]==0){if(eximp[v1]==1)printf("ERROR: %d is not found.\n",v2);else if(eximp[v2]==1)printf("ERROR: %d is not found.\n",v1);else printf("ERROR: %d and %d are not found.\n",v1,v2);continue;}Node* p = nmp[v1];Node* q = nmp[v2];int LCA = vmp[getLCA(p,q)];if(LCA==v1||LCA==v2)printf("%d is an ancestor of %d.\n",LCA==v1?v1:v2,LCA==v1?v2:v1);else printf("LCA of %d and %d is %d.\n",v1,v2,LCA);}return 0;
}

相关文章:

cf 414B Mashmokh and ACM 动态规划

题目链接&#xff1a;http://codeforces.com/problemset/problem/414/B dp[i][j]表示长度为i、最后一个数字为j的合法序列总数 dp[1][1...2000]都是1 后面用dp[i-1][j] 去更新 dp[i][j*t] (1 < j*t < 2000) 即用因子去更新它的倍数 表面上看是2000^3的复杂度会爆 其实不用…

解决:angularjs radio默认选中失效问题

添加ng-model后checked"checked"失效&#xff0c;可见angularjs也不好&#xff0c;会失效html标准属性解决&#xff1a;添加ng-checked"1"<input type"radio" ng-model"sel_course" value"1" ng-checked"1" /…

在ireport报错 报 jdk5找不到的解决办法

在ireport安装目录下&#xff0c; etc目录下有ireport.conf&#xff0c; 其中有jkdhome设置&#xff0c; 把前面的#&#xff08;注释&#xff09;去掉&#xff0c; 换成自己的jdk目录就行 双引号不要去掉 jdk地址放在双引号之间 比如 改成 jdkhome"G:/ACD/jdk1.5.0&quo…

如何通过中序和层序序列建立二叉树

有这样一棵二叉树 根据节点个数 9 层序遍历结果 15 23 8 16 2 32 28 7 11 中序遍历结果 16 23 7 32 11 2 28 15 8 预期先序输出 15 23 16 2 32 7 11 28 8 运行结果 这个过程和建立二叉查找树(BST)的过程是非常相像的&#xff0c;将laSq[laIndex]插入到根为root的子树中&a…

BZOJ 3573 米特运输

Description 米特是D星球上一种非常神秘的物质&#xff0c;蕴含着巨大的能量。在以米特为主要能源的D星上&#xff0c;这种米特能源的运输和储存一直是一个大问题。 D星上有N个城市&#xff0c;我们将其顺序编号为1到N&#xff0c;1号城市为首都。这N个城市由N-1条单向高速通…

[学习笔记]最小割之最小点权覆盖最大点权独立集

最小点权覆盖 给出一个二分图&#xff0c;每个点有一个非负点权要求选出一些点构成一个覆盖&#xff0c;问点权最小是多少 建模&#xff1a; S到左部点&#xff0c;容量为点权 右部点到T&#xff0c;容量为点权 左部点到右部点的边&#xff0c;容量inf 求最小割即可。 证明&…

10分钟学会Google Map API

http://space.itpub.net/14734354/viewspace-374828 前几天玩了玩Google的Map API&#xff0c;感觉还不错&#xff0c;很简单。但凡有过任何编程经验的同学&#xff0c;看完以下的教程&#xff0c;都可以在10分钟内掌握它的主要功能。另外我还做了个简单的小例子&#xff0c;有…

1143 Lowest Common Ancestor(建树与不建两种思路)

目录 解法一 解法二 解法一 这题可以不建树&#xff0c;直接利用BST的性质&#xff1a;左子树<根节点<右子树&#xff0c;对先序序列进行遍历&#xff0c;如果有某个元素大于等于u,v中较小的且小于等于u,v中较大的&#xff0c;则可能是根节点。 这题数据弱&#xff0…

UIScrollView

UIScrollView&#xff08;包括它的子类 UITableView 和 UICollectionView&#xff09;是 iOS 开发中最常用也是最有意思的 UI 组件&#xff0c;大部分 App 的核心界面都是基于三者之一或三者的组合实现。UIScrollView 是 UIKit 中为数不多能响应滑动手势的 view&#xff0c;相比…

MySQL练习题:常用函数

1. 以首字母大写&#xff0c;其他字母小写的方式显示所有员工的姓名2. 将员工的职位用小写字母显示3. 显示员工姓名超过5个字符的员工名4. 用#来填充员工职位job的结尾处&#xff0c;按10个字符长度输出。5. 去除字符串 hello world 两边的空格&#xff0c;并将单词间的空格改…

我的WINCE4.2历程(10)

2010-04-02 今天的主要工作&#xff1a; 1&#xff09;RTC4513驱动调试&#xff0c;又做了一些尝试&#xff08;检查GPIO口的第二功能设置是否正常&#xff09;&#xff0c;结果还是不正常&#xff0c;FAINT。 2&#xff09;回顾了截止到目前取得的进展&#xff1a; a&#xff…

1069 The Black Hole of Numbers

注意两点&#xff1a; 1. 不足4位要补足&#xff0c;不仅仅是一开始要考虑&#xff0c;每次得到一个差值&#xff0c;都要考虑 2. 到0也会停下&#xff0c;不仅仅是一开始可能发生&#xff0c;也可能是过程中的某一个差值 另&#xff1a; vector<int> 是可以作为函数…

详解Asp.net MVC DropDownLists

来自网络&#xff1a; Asp.net MVC中的DropDownLists貌似会让一开始从Asp.net Forms转过来的程序员造成不少迷惑.这篇文章讲述了为了使用DropDownLists,你需要在Asp.Net MVC中知道的方方面面. DropDownList,ComboBox,无论你喜欢怎么称呼这些&#xff0c;他们毫无例外的会被生成…

3D中的OBJ文件格式详解(转载)

OBJ文件是Alias|Wavefront公司为它的一套基于工作站的3D建模和动画软件"Advanced Visualizer"开发的一种标准3D模型文件格式&#xff0c;很适合用于3D软件模型之间的互导&#xff0c;也可以通过Maya读写。比如你在3dsMax或LightWave中建了一个模型&#xff0c;想把它…

比特币测试网络搭建

转自 https://blog.csdn.net/yzpbright/article/details/81004202 比特币 一、安装 Docker 二、安装和运行比特币测试网络(bitcoin-testnet) 1.下载比特币测试网络(bitcoin-testnet)的Docker镜像 docker pull freewil/bitcoin-testnet-box 2.运行Docker镜像 docker run -t -i -…

1136 A Delayed Palindrome 需再做

注意点&#xff1a; 1. 大整数即高精度整数&#xff0c;数据结构bign要会定义 2. 记得写构造函数或者通过别的方式初始化bign 3. len属性记得手动更新 4. int d[maxn]数组是顺位存储&#xff0c;意味着字符串要逆序读入 AC代码 #include<cstdio> #include<iostr…

ES5-Array-push(),pop(),shift(),unshift()

参考文章&#xff1a;push()&#xff0c;pop() push方法用于在数组的末端添加一个或多个元素&#xff0c;并返回添加新元素后的数组长度。 注意&#xff0c;该方法会改变原数组&#xff0c;而不是创建一个新的数组。var arr [];arr.push(1) // 1 arr.push(a) // 2 arr.push(tr…

visual studio 2005 新建C++空项目无法调试的解决方案

(1)项目属性→配置属性→链接器从→调试→生成调试信息→将“否”改为“是(/DEBUG)”。(2)项目属性→配置属性→C/C→调试信息格式→将“禁用”改为“用于编辑并继续的程序数据库(/ZI)”。(3)项目属性→配置属性→C/C→优化→优化→将“最大化速度(/O2)”改为“禁用(/Od)”。转…

jQuery.append()、jQuery.html()存在的XSS漏洞

使用jQuery.append()、jQuery.html()方法时&#xff0c;如果其中内容包含<script>脚本而没有经过任何处理的话&#xff0c;会执行它。 简单的示例代码如下&#xff1a; 1 var xssStr <script>console.log(1)</script>; 2 $(#test).html(xssStr); 控制台会打…

1132 Cut Integer

注意&#xff1a;取余得到的后半段b可能为0&#xff0c;所以要预先判断&#xff0c;否则会出现浮点错误。 写成 if(b!0&&z%(a*b)0)是不能避免浮点错误的&#xff0c;因为z%(a*b)已经发生。需要更换两个条件的位置&#xff0c;把前提放在前面&#xff0c;即 if(b!0&am…

.net之工作流工程展示及代码分享(二)工作流引擎

在介绍完表单类的时候&#xff0c;接下来介绍工作流引擎&#xff0c;主要由四个类组成&#xff0c;分别是流程、流程步骤、流程实例、流程步骤实例类。 流程类&#xff1a; 1 [Serializable]2 public class Flow3 {4 [XmlAttribute]5 public Guid …

11.CCNA第十一天-配置OSPF/EIGRP(增强型内部网关协议)

配置OSPFBranch(config)#router ospf ?<1-65535> Process ID通配符掩码在IGP协议中&#xff0c;以连续的0和连续的1组成有一种不科学的称呼&#xff08;反掩码&#xff09;Branch#show running-config | section router ospfrouter ospf 10network 10.1.0.0 0.0.255.25…

Electio Time poj

第一次用结构体&#xff0c;写些自己的心得&#xff1a; #include<stdio.h> #include<algorithm> using namespace std; #define MAX 50000 struct COW //定义结构体&#xff0c;&#xff08;由于在cmp&#xff08;&#xff09;函数里需要用到结构体名&#xf…

浙江大学软件学院2020年保研上机模拟练习 7-3 Partial School Ranking

并查集的使用时注意&#xff1a; 1. 合并两个结点是 F[sa] sb 而不是 sb F[sa]&#xff0c;想一下含义。 2. 给每个结点赋予其自身为父节点时&#xff0c;要先判断它的父节点是不是0&#xff0c;也许已经有了。 我把照片里其他同学的成绩赋值为0&#xff0c;但是应该考虑到…

小米:开源不仅要站在巨人的肩膀上,还要为巨人指方向

今天上午&#xff0c;第一届小米开源技术峰会在北京举行&#xff0c;会上&#xff0c;小米人工智能与云平台副总裁崔宝秋致开场词&#xff0c;并发表了《小米开源之路》的演讲。 崔宝秋强调小米一直在推动开源&#xff0c;也是开源的倡导者。他告诉我们雷军创立小米的其中一个重…

微软企业库4.1学习笔记(七)创建对象 续集1

3.2使用Unity模块创建企业库对象 下面介绍如何使用前面的方法获取企业库对象的实例。代码示例如下 IUnityContainer containter newUnityContainer(); containter.AddNewExtension<EnterpriseLibraryCoreExtension>();首先创建一个Unity容器&#xff0c;并且添…

如何把 XML 文件显示为 HTML 表格

如何把 XML 文件显示为 HTML 表格 <html><head><script type"text/javascript">var xmlhttp; function loadXMLDoc(url){xmlhttpnull;if (window.XMLHttpRequest) {// code for IE7, Firefox, Mozilla, etc. xmlhttpnew XMLHttpRequest(); }else i…

浙江大学软件学院2020年保研上机模拟练习 7-2 Distance of Triples

思路一&#xff1a; 3个数组都按照小到大排序&#xff0c;设置3个指针&#xff0c;起始都在数组的末尾&#xff0c;如果1个指针向前移动1位可以让对应元素和另两个数组元素的距离之和减小&#xff0c;则移动它。如果某一回合三个指针都没动&#xff0c;就跳出循环。 非满分&a…

docker的分层

docker的分层 Contents docker的层docker的层是怎么来的docker是如何区分这些层 docker镜像是如何区分这些层的docker的层在本地的存储 vfsdevicemapperdocker的层 在这里&#xff0c;我们首先做一个样例&#xff0c;样例设定为一个镜像D。当然&#xff0c;这个D镜像不是单层&a…

《跟菜鸟学Cisco UC部署实战》-第 1 章 规划-课件(一共12章,免费)

链接:https://pan.baidu.com/s/1RiIphSUG5dsbPPqWaynHjQ 提取码:xjp9 复制这段内容后打开百度网盘手机App,操作更方便哦 《跟菜鸟学Cisco UC部署实战》-视频课程http://edu.51cto.com/course/10031.html 《Skype for Business Server 2015-企业外部-部署》视频课程http://ed…