首先是鬼鬼珊的闲聊一分钟
今天给大家扯一点什么呢?好吧,最近的论文看得我想哭,最悲伤的事是看不懂呀,尤其是国外研究的论文,一个句子长到我还要进行英文的长难句解析才勉强搞得清楚其中的深刻含义,导致我每天都想躺尸。说起来还有一件事值得一提,很久之前和朋友聊天,说起恋爱这个事,她以一个过来人的经验告诉我,在恋爱中尽量不要作,不要乱发脾气。因此,我为了促进自我良好的恋爱发展进行了深刻的调研,调研平台为知乎,哈哈哈,比如,男生喜欢什么样性格的女孩子,从上面的回答进行了认真自我反思,以尽量避免。这样看起来我还比较机智,仔细想想我可真是个魔鬼,哈哈哈。突然还有一句想说,就是这个富文本编辑器可真的太好用了吧,之前一直用的是Markdown编辑器,哇,今天的体验真的太不一样了。
好了,言归正传
The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.
Given any two nodes in a binary tree, you are supposed to find their LCA.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.
Output Specification:
For each given pair of U and V, print in a line
LCA of U and V is A.
if the LCA is found andA
is the key. But ifA
is one of U and V, printX is an ancestor of Y.
whereX
isA
andY
is the other node. If U or V is not found in the binary tree, print in a lineERROR: U is not found.
orERROR: V is not found.
orERROR: U and V are not found.
.Sample Input:
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
Sample Output:
LCA of 2 and 6 is 3. 8 is an ancestor of 1. ERROR: 9 is not found. ERROR: 12 and -3 are not found. ERROR: 0 is not found. ERROR: 99 and 99 are not found.
题目含义
在一棵二叉树中,找出两个节点的最小祖先,输入为二叉树访问的中序和先序,需要进行检测的节点u和v,如果其中有一个节点不在这棵树中,就输出这个节点找不到,两个节点都不在树中,就输出两个节点都找不到。如果u和v都在二叉树中,分两种情况,第一种为其中一个节点是另一个节点的祖先节点,第二种两个节点的共同最小祖先节点是第三个节点。对于不同的情况进行输出即可。
思路(仅是鬼鬼珊个人思路,其他更好的idea欢迎交流-_-)
- 首先我根据二叉树的中序访问和先序访问构建了二叉树(之前有一篇博客是关于根据中序访问和后序访问构建二叉树,但那道题好像可以不用构建二叉树也可以做,maybe这道题也可以,我猜的,哈哈哈,有时候不得不膜拜大神们解题的思路),对于每一个节点,都存放它的父亲节点的位置(即在访问先序中的索引---数组下标)
- 构建好二叉树,就可以进行处理了,当其中某个节点不在二叉树中,就直接输出xx is not found,或者两个节点都不在数中,输出u and v are not found,具体实现就是去遍历一下二叉树吧,或者直接用u和v去任一一个访问顺序匹配一下,看能不能找到。
- 当这两个节点都在二叉树中,我分了三步,第一步:将两个节点走到同一层,u的层次比v的大(根节点为第一层,同理u和v在同一层或者v的层次比v大也可以类推),这个时候v就有可能是u的祖先节点了,从u开始,根据二叉树,往上走,直到走到temp和v一个level。第二步:当两个节点在同一层时,比较一下此时走到的索引值temp是不是和v的索引值相等(我在我自己的code是比较value值,这里写的时候,似乎索引值也可以)。如果相等,就说嘛v是u的祖先,不相等,进行第三步。第三步:这个时候将temp和v一起往上走,直到两个走到一个共同的祖先节点即可。
- 根据不同的情况按照输出要求进行输出即可。
如图所示,展示了两种情况
图一:找3和4的祖先
图2:找4和8的共同祖先
根据二叉树的访问中序和先序构建二叉树
就以这个题为例,
7 2 3 4 6 5 1 8 二叉树访问中序 5 3 7 2 6 4 8 1 二叉树访问先序
首先,先序的第一个节点肯定就是整棵树的根节点5,root=0,到中序去找到5这个节点的索引值5(下标从0开始),就可以知道左子树有5个节点,右子树有2个节点。左子树的根节点就可以找到root+1,将这个节点的父节点设置为root,右子树的根节点为root+(左子树的个数)+1,也将这个节点的根节点设置为root,然后递归处理左子树和右子树,直到没有元素时跳出递归。图解如下图所示:
贴代码啦
#include <iostream>
#include<bits/stdc++.h>
#define MaxSize 10001
using namespace std;
struct Node{
int value; //节点的值
int parent; //父节点的索引值
int level; //存放节点所在的层次
};
int M,N;
int inOrder[MaxSize];
Node preOrder[MaxSize];
//构造二叉树
void Conduct_Tree(int left,int right,int root){
int k,i;
int total=right-left+1;
if(total<=0){return;} //没有元素,跳出递归
for(i=left;i<=right;i++){
if(inOrder[i]==preOrder[root].value){
k=i-left; //左子树有多少个元素
break;
}
}
if(k>0){
preOrder[root+1].parent=root; //设置左子树的根节点的父节点
preOrder[root+1].level=preOrder[root].level+1; //设置右子树的根节点所在的level
}
if(total-k-1>0){
preOrder[root+k+1].parent=root;
preOrder[root+k+1].level=preOrder[root].level+1;
}
Conduct_Tree(left,i-1,root+1); //递归处理左子树
Conduct_Tree(i+1,right,root+k+1); //递归处理右子树
}
void Process(int u,int v){
bool f1=false,f2=false;
int index1,index2;
int temp;
for(int i=0;i<N;i++){ //找出这棵二叉树中是否有处理的这两个节点值(输入的两个节点是一模一样的时候要注意一下)
if(preOrder[i].value==u){
index1=i;
f1=true;
}
if(preOrder[i].value==v){
index2=i;
f2=true;
}
if(f1&&f2){
break;
}
}
if(f1&&f2){
if(preOrder[index1].level>preOrder[index2].level){ //先判断谁的层次要高一些,就移动谁,移到同一个level
temp=preOrder[index1].parent;
while(preOrder[temp].level>preOrder[index2].level){
temp=preOrder[temp].parent;
}
if(preOrder[temp].value==preOrder[index2].value){ //移到一个level之后,看是否其中一个节点是另一个节点的祖先节点
cout<<v<<" is an ancestor of "<<u<<"."<<endl;
}
else{
while(preOrder[temp].value!=preOrder[index2].value){ //移到同一level之后,将两个节点继续往上走,知道共同的祖先
temp=preOrder[temp].parent;
index2=preOrder[index2].parent;
}
cout<<"LCA of "<<u<<" and "<<v<<" is "<<preOrder[temp].value<<"."<<endl;
}
}
else if(preOrder[index1].level==preOrder[index2].level){
if(preOrder[index1].value==preOrder[index2].value){
cout<<u<<" is an ancestor of "<<v<<"."<<endl;
}
else{
while(preOrder[index1].value!=preOrder[index2].value){
index1=preOrder[index1].parent;
index2=preOrder[index2].parent;
}
cout<<"LCA of "<<u<<" and "<<v<<" is "<<preOrder[index1].value<<"."<<endl;
}
}
else{
temp=preOrder[index2].parent;
while(preOrder[temp].level>preOrder[index1].level){
temp=preOrder[temp].parent;
}
if(preOrder[temp].value==preOrder[index1].value){
cout<<u<<" is an ancestor of "<<v<<"."<<endl;
}
else{
while(preOrder[temp].value!=preOrder[index1].value){
temp=preOrder[temp].parent;
index1=preOrder[index1].parent;
}
cout<<"LCA of "<<u<<" and "<<v<<" is "<<preOrder[temp].value<<"."<<endl;
}
}
}
else if(!f1&&f2){
cout<<"ERROR: "<<u<<" is not found."<<endl;
}
else if(f1&&!f2){
cout<<"ERROR: "<<v<<" is not found."<<endl;
}
else{
cout<<"ERROR: "<<u<<" and "<<v<<" are not found."<<endl;
}
}
int main()
{
int u,v;
cin>>M>>N;
for(int i=0;i<N;i++){
cin>>inOrder[i];
}
for(int i=0;i<N;i++){
cin>>preOrder[i].value;
}
preOrder[0].parent=-1;
preOrder[0].level=1;
Conduct_Tree(0,N-1,0);
/**
for(int i=0;i<N;i++){
cout<<preOrder[i].value<<" "<<preOrder[i].parent<<" "<<preOrder[i].level<<endl;
}**/
for(int i=1;i<=M;i++){
cin>>u>>v;
Process(u,v);
}
return 0;
}