// 20230029版本重做
class Solution {
public TreeNode deduceTree(int[] preorder, int[] inorder) {
if (preorder.length == 0 || inorder.length == 0) {
return null;
}
return myDeduce(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
}
public TreeNode myDeduce(int[] preorder, int[] inorder,
int preStart, int preEnd,
int inStart, int inEnd) {
if (preStart > preEnd || inStart > inEnd) {
return null;
}
int rootVal = preorder[preStart], rootIndexOfInorder = inStart;
TreeNode root = new TreeNode(rootVal);
for (int i = inStart; i <= inEnd; ++i) {
if (inorder[i] == rootVal) {
rootIndexOfInorder = i;
break;
}
}
int leftSize = rootIndexOfInorder - inStart;
root.left = myDeduce(preorder, inorder, preStart + 1, preStart + leftSize,
inStart, rootIndexOfInorder - 1);
root.right = myDeduce(preorder, inorder, preStart + leftSize + 1, preEnd,
rootIndexOfInorder + 1, inEnd);
return root;
}
}
// 20231115,原始代码,太过冗余
class Solution {
public TreeNode deduceTree(int[] preorder, int[] inorder) {
if (preorder.length == 0 || inorder.length == 0) {
return null;
}
List<Integer> preOrderList = new ArrayList<>();
List<Integer> inOrderList = new ArrayList<>();
for (int i = 0; i < preorder.length; ++i) {
preOrderList.add(preorder[i]);
}
for (int i = 0; i < inorder.length; ++i) {
inOrderList.add(inorder[i]);
}
int rootVal = preOrderList.get(0);
int rootInx = -1;
for (int i = 0; i < inOrderList.size(); ++i) {
if (inorder[i] == rootVal) {
rootInx = i;
break;
}
}
List<Integer> leftPreList = preOrderList.subList(1, rootInx + 1); // 左前序
List<Integer> rightPreList = preOrderList.subList(rootInx + 1, preOrderList.size()); // 右前序
List<Integer> leftInList = inOrderList.subList(0, rootInx); // 左中序
List<Integer> rightInList = inOrderList.subList(rootInx + 1, inOrderList.size()); // 右中序
int[] leftPreArray = new int[leftPreList.size()];
int[] rightPreArray = new int[rightPreList.size()];
int[] leftInArray = new int[leftInList.size()];
int[] rightInArray = new int[rightInList.size()];
for (int i = 0; i < leftPreList.size(); ++i) {
leftPreArray[i] = leftPreList.get(i);
}
for (int i = 0; i < rightPreList.size(); ++i) {
rightPreArray[i] = rightPreList.get(i);
}
for (int i = 0; i < leftInList.size(); ++i) {
leftInArray[i] = leftInList.get(i);
}
for (int i = 0; i < rightInList.size(); ++i) {
rightInArray[i] = rightInList.get(i);
}
TreeNode leftNode = deduceTree(leftPreArray, leftInArray);
TreeNode rightNode = deduceTree(rightPreArray, rightInArray);
return new TreeNode(rootVal, leftNode, rightNode);
}
}
// 20231115,优化下代码结构
class Solution {
public TreeNode deduceTree(int[] preorder, int[] inorder) {
if (preorder.length == 0 || inorder.length == 0) {
return null;
}
List<Integer> preOrderList = new ArrayList<>();
List<Integer> inOrderList = new ArrayList<>();
for (int i = 0; i < preorder.length; ++i) {
preOrderList.add(preorder[i]);
}
for (int i = 0; i < inorder.length; ++i) {
inOrderList.add(inorder[i]);
}
return myFunc(preOrderList, inOrderList);
}
public TreeNode myFunc(List<Integer> preOrderList, List<Integer> inOrderList) {
if (preOrderList.size() == 0) {
return null;
}
int rootVal = preOrderList.get(0);
int rootInx = -1;
for (int i = 0; i < inOrderList.size(); ++i) {
if (inOrderList.get(i) == rootVal) {
rootInx = i;
break;
}
}
List<Integer> leftPreList = preOrderList.subList(1, rootInx + 1); // 左前序
List<Integer> rightPreList = preOrderList.subList(rootInx + 1, preOrderList.size()); // 右前序
List<Integer> leftInList = inOrderList.subList(0, rootInx); // 左中序
List<Integer> rightInList = inOrderList.subList(rootInx + 1, inOrderList.size()); // 右中序
TreeNode leftNode = myFunc(leftPreList, leftInList);
TreeNode rightNode = myFunc(rightPreList, rightInList);
return new TreeNode(rootVal, leftNode, rightNode);
}
}
一个小知识点:已知二叉树的中序遍历和前序遍历(或后序遍历)结果则可以确定该二叉树;但是通过二叉树的前序遍历和后序遍历结果无法确定该二叉树!!!
##Solution1:
根据书中算法写的c++版本的代码,不知为何,未能AC…
下面代码有bug,但找了好久木找到。。。。
2018年3月15日更新:在师兄的帮助下,bug找到了。。。
bug在
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { //pre vin中分别是前序和后序遍历的结果
int n_pre = pre.size(),n_vin = vin.size();
if(n_pre == 0 || n_vin == 0)
return NULL;
return BuildTree(0,n_pre-1,0,n_vin-1,pre,vin);
}
struct TreeNode* BuildTree(int prestart,int preend,int vinstart,int vinend,vector<int> &pre_vec,vector<int> &vin_vec){
//前序遍历序列的第一个数字是根结点的值
int rootValue = pre_vec[prestart];
struct TreeNode* root = new TreeNode(rootValue);
root->left = root->right = NULL;
if(prestart == preend){
if(vinstart == vinend && pre_vec[prestart] == vin_vec[vinstart])
return root;
else
std::cout<<"Invalid input."<<std::endl;
}
//在中序遍历中找到根结点的值
int rootInvin = vinstart;
while(rootInvin <= vinend && vin_vec[rootInvin] != rootValue)
++rootInvin;
if(rootInvin == vinend && vin_vec[rootInvin]!=rootValue)
std::cout<<"Invalid input."<<std::endl;
//int leftlength=rootInvin-prestart;总是犯这种傻逼错误,而瞎耽误时间
int leftlength=rootInvin-vinstart;
int leftpreend=prestart+leftlength;
if(leftlength>0){//构建左子树,若取等号则左子树为空,没必要构建
root->left = BuildTree(prestart+1,leftpreend,vinstart,rootInvin-1,pre_vec,vin_vec);
}
if(leftlength+prestart<preend){//构建右子树,若取等号则右子树为空,没必要构建
root->right = BuildTree(leftpreend+1,preend,rootInvin+1,vinend,pre_vec,vin_vec);
}
return root;
}
};
##Solution2:c++中排名第一的答案
理论上浪费了空间,但是实现起来简单了很多。。。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
int inlen=in.size();
if(inlen==0)
return NULL;
vector<int> left_pre,right_pre,left_in,right_in;
//创建根节点,根节点肯定是前序遍历的第一个数
struct TreeNode* head=new TreeNode(pre[0]);
//找到中序遍历根节点所在位置,存放于变量gen中
int gen=0;
for(int i=0;i<inlen;i++){
if (in[i]==pre[0]){
gen=i;
break;
}
}
//对于中序遍历,根节点左边的节点位于二叉树的左边,根节点右边的节点位于二叉树的右边
//利用上述这点,对二叉树节点进行归并
for(int i=0;i<gen;i++){
left_in.push_back(in[i]);
left_pre.push_back(pre[i+1]);//前序第一个为根节点
}
for(int i=gen+1;i<inlen;i++){
right_in.push_back(in[i]);
right_pre.push_back(pre[i]);
}
//和shell排序的思想类似,取出前序和中序遍历根节点左边和右边的子树
//递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点
head->left=reConstructBinaryTree(left_pre,left_in);
head->right=reConstructBinaryTree(right_pre,right_in);
return head;
}
};
##20180830重做
通过中序+前序/后序遍历结果重建二叉树的写法基本差不多,牢记!!!
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if (!pre.size() || !vin.size()) return NULL;
TreeNode* root;
root = my_build(pre, vin);
return root;
}
TreeNode* my_build(vector<int> pre, vector<int> vin) {
if (!pre.size()) return NULL;//为空返回空指针,即叶子结点
TreeNode* root = new TreeNode(pre[0]);//建立根结点
vector<int> left_pre, right_pre, left_in, right_in;
//找到根结点的值在中序遍历中的位置
int root_val_mark = 0;
for (int i = 0; i < vin.size(); i++) {
if (vin[i] == pre[0]) {
root_val_mark = i;
break;
}
}
//构造左子树序列
for (int i = 0; i < root_val_mark; i++) {
left_pre.push_back(pre[i+1]);
left_in.push_back(vin[i]);
}
//构造右子树序列
for (int i = root_val_mark + 1; i < pre.size(); i++) {
right_pre.push_back(pre[i]);
right_in.push_back(vin[i]);
}
//递归走起!
root->left = my_build(left_pre, left_in);
root->right = my_build(right_pre, right_in);
return root;
}
};