1119. Pre- and Post-order Traversals(前序后序 转中序)

1119 Pre- and Post-order Traversals (30 分)

Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences, or preorder and inorder traversal sequences. However, if only the postorder and preorder traversal sequences are given, the corresponding tree may no longer be unique.

Now given a pair of postorder and preorder traversal sequences, you are supposed to output the corresponding inorder traversal sequence of the tree. If the tree is not unique, simply output any one of them.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤ 30), the total number of nodes in the binary tree. The second line gives the preorder sequence and the third line gives the postorder sequence. All the numbers in a line are separated by a space.

Output Specification:

For each test case, first printf in a line Yes if the tree is unique, or No if not. Then print in the next line the inorder traversal sequence of the corresponding binary tree. If the solution is not unique, any answer would do. It is guaranteed that at least one solution exists. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input 1:

7
1 2 3 4 6 7 5
2 6 7 4 5 3 1

Sample Output 1:

Yes
2 1 6 4 7 3 5

Sample Input 2:

4
1 2 3 4
2 4 3 1

Sample Output 2:

No
2 1 3 4

参考柳神大佬的代码 : https://www.liuchuo.net/archives/2484

本题题意 就是给出前序 后序遍历  输出其中一个中序遍历;

本题思路: 因为前序 后序 转换成中序的结果并不是唯一的 (eg : 前序 AB  后序为 BA ) 并不知道B结点在根结点的A的左边或是右边,因此判断是否存在唯一解 如果结点只存在一个子结点 那么解就不是唯一的(就存在了两种选择,如果有n个这样的子结点,选择就是  2 的 n次方)) 但此题只需给出唯一解, 因此只需要假设存在单个子结点的情况连着根结点的右结点,

进行判断时, 通过先序遍历 和 后序遍历 找到根结点 ,  又因为要找到 中序遍历(左 根 右 的顺序) 因此还要通过递归找到先序遍历 和后序遍历 的 左子树的根,  然后 遍历 通过递归找到先序遍历 和后序遍历 的 右子树的根 (为什么先序和后序遍历 都需要遍历左子树 和 右子树) 因为只有先序 和 后序 都知道 才能确定左子树结点个数 和 右子树 结点个数 确定递归的范围,

如何找到对应的根节点 首先 pre [preleft] == post[postright] (根结点要相等) 此时找到 后序遍历中右根结点 就是 post[postright - 1] ,然后找到先序遍历中 与 post[postright - 1]相等的结点下标 i ,此时 i 为先序遍历的右结点(当然这是假设的右结点( 如果根节点的子结点为单节点就不确定左与右))(如果 i - preleft 小于等于 1 就说明根结点只存在一个结点(假设为右结点就不存在左结点) )此时通过i(假设指向的根的右结点)能够计算出先序遍历,后序遍历左子树索引位置,

i - preleft - 1 就是左子树结点的个数,

inOrder(preleft + 1, i - 1, postleft, postleft + (i - preleft - 1) -1);

能够计算出计算出先序遍历,后序遍历右子树索引位置,

inOrder(i, preright, postleft + (i - preleft -1), postright - 1);

具体代码实现:

/**
	假设此时的根连着的右子树
**/
#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> in, pre, post;
bool isUnique = true;
void inOrder(int preleft,int preright,int postleft,int postright){
	if(preleft == preright){ //只有一个结点了 直接加入进in数组中  也可以判断 < 直接返回 但是这样会多判定一次 
		in.push_back(pre[preleft]);
		return;
	}
	if(pre[preleft] == post[postright]){
		int i = preleft + 1;//i需要指向先序遍历中的右子树的根结点(当pre[i] 与 Post[postright - 1]相等时),
		while(pre[i] != post[postright - 1]) i++;
		if(i - preleft > 1){ //表示此时的结点是独一无二的(先序遍历中 右根结点左边依然存在左结点) 
			inOrder(preleft + 1, i - 1, postleft, postleft + (i - preleft - 1) -1); //进入先序遍历的左子树, 和后序遍历的左子树 
		}else{ //表示根结点只连着一个结点, 不能判断是左子树或是右子树 
			isUnique = false;
		}	
		in.push_back(pre[preleft]);
		inOrder(i, preright, postleft + (i - preleft -1), postright - 1);
		
	}
}

int main(){
	scanf("%d", &n);
	pre.resize(n);
	post.resize(n);
	for(int i = 0; i < n; i++){
		scanf("%d", &pre[i]);
	}
	for(int i = 0; i < n; i++){
		scanf("%d", &post[i]);
	}
	inOrder(0, n - 1, 0, n - 1);
	printf("%s\n", isUnique ==	 true ? "Yes" : "No");
	for(int i = 0; i < n; i++){
		if(i != 0)
			printf(" ");
		printf("%d", in[i]);
	}
	printf("\n");  //注意最后的格式 还要输处 \n 
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41698081/article/details/91401896