0
点赞
收藏
分享

微信扫一扫

[二叉树]BM40 重建二叉树-中等

​​BM40 重建二叉树​​

描述

给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。

[二叉树]BM40 重建二叉树-中等_恢复二叉树


提示:1.vin.length == pre.length2.pre 和 vin 均无重复元素3.vin出现的元素均出现在 pre里4.只需要返回根结点,系统会自动输出整颗树做答案对比数据范围:[二叉树]BM40 重建二叉树-中等_二叉树_02,节点的值 [二叉树]BM40 重建二叉树-中等_恢复二叉树_03要求:空间复杂度 [二叉树]BM40 重建二叉树-中等_二叉树_04,时间复杂度 [二叉树]BM40 重建二叉树-中等_二叉树_04

示例1

输入:

[1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6]

复制返回值:

{1,2,3,4,#,5,6,#,7,#,#,8}

复制说明:

返回根节点,系统会输出整颗二叉树对比结果,重建结果如题面图示

示例2

输入:

[1],[1]

复制返回值:

{1}

复制

示例3

输入:

[1,2,3,4,5,6,7],[3,2,4,1,6,5,7]

复制返回值:

{1,2,5,3,4,6,7}

题解

前序遍历、中序遍历恢复二叉树的递归解法

对于一颗二叉树,有三种深度优先遍历——前序、中序、后序,如果提供中序遍历和其他两个遍历的任意一个,可以恢复原来的二叉树。

对于前序遍历:第一个节点为根结点,之后是左子树、右子树

对于中序遍历:则是左子树、根结点、右子树

我们可以先在前序遍历中确定根结点,然后再在中序遍历中找到这个节点的索引,该索引的左边就是左子树,右边就是右子树。此时我们可以根据左子树的长度、右子树的长度找到前序遍历中左子树、右子树的边界。然后递归求解。


[二叉树]BM40 重建二叉树-中等_恢复二叉树_06

实现代码如下:

// https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
#include <bits/stdc++.h>

struct TreeNode
{
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

int find_val(std::vector<int> &nums, int left, int right, int val)
{
while (left != right)
{
if (nums[left] == val)
{
return left;
}
left++;
}
return right;
}

TreeNode *build_tree(std::vector<int> &pre, int pre_begin, int pre_end, std::vector<int> &in, int in_begin, int in_end)
{
if (pre_begin == pre_end || in_begin == in_end)
{
return nullptr;
}
auto node = new TreeNode(pre[pre_begin]);
int index = find_val(in, in_begin, in_end, node->val);
int left_count = index - in_begin;
int right_count = in_end - index - 1;
node->left = build_tree(pre, pre_begin + 1, pre_begin + 1 + left_count, in, in_begin, index);
node->right = build_tree(pre, pre_begin + 1 + left_count, pre_end, in, index + 1, in_end);
return node;
}


TreeNode *reConstructBinaryTree(std::vector<int> pre, std::vector<int> vin)
{
return build_tree(pre, 0, pre.size(), vin, 0, vin.size());
}


后遍历、中序遍历恢复二叉树的递归解法

思路和前序遍历、中序遍历恢复二叉树的思路一样。只需要将后序遍历进行逆序,实现就和之前一样了,这里直接写代码:

template <typename T>
using vec_riter = decltype(std::vector<T>().rbegin());

// 后续序列和中序序列恢复二叉树
// 思路和前序、中序恢复二叉树一样
template <typename T>
treenode<T> *recover_from_post_and_in_order_imp(vec_riter<T> post_rbegin,vec_riter<T> post_rend,
vec_iter<T> in_begin,vec_iter<T> in_end)
{
if (post_rbegin == post_rend || in_begin == in_end || std::distance(post_rbegin,post_rend) != std::distance(in_begin,in_end))
{
return nullptr;
}

vec_iter<T> index = std::find(in_begin,in_end,*post_rbegin);
if (index == in_end)
{
return nullptr;
}
treenode<T> *root = new treenode<T>(*post_rbegin);
size_t right_length = std::distance(index,in_end) - 1;// 右子树的节点数
root->left = recover_from_post_and_in_order_imp<T>(post_rbegin + right_length + 1,post_rend,in_begin,index);
root->right = recover_from_post_and_in_order_imp<T>(post_rbegin+1,post_rbegin+1+right_length,index + 1,in_end);
return root;
}


template <typename T>
treenode<T> *recover_from_post_and_in_order(std::vector<T> &post_order,std::vector<T> &in_order)
{
if (post_order.empty() || post_order.size() != in_order.size())
{
return nullptr;
}
return recover_from_post_and_in_order_imp<T>(post_order.rbegin(),post_order.rend(),in_order.begin(),in_order.end());
}


举报

相关推荐

0 条评论