21-3-3 leetcode题目:重建二叉树

数据结构与算法这东西是应该经过不断地勤学苦练才能保持手感的,尤其是对于我这样没有天赋的选手,刷题是不能停的,而且在刷题的同时,我还应该保持不断地记录,方能留下复盘的机会。这也是我为什么要开一个博客的原因。加油!

题目概述

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

返回如下的二叉树:

    3
   / \
  9  20
/  \
   15   7

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

本题要注意的细节较为繁多,大概有如下几点:

- (前序遍历&&中序遍历)||(中序遍历&&后序遍历)是确定一颗唯一二叉树的充要条件。

- 前序遍历数组中首位数为二叉树的根节点。前序遍历的结果形式为`[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]`,且**分别处于左子树与右子树区间临界的两个值分别为左右子树的根节点。**

- 中序遍历的结果形式如下:`[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]`

在掌握这些小细节以后,就可以开始理解本题的思路了。

本题主要是应用了分治思想。你肯定知道:一用到分治思想就离不开递归。对于递归我是这样理解的:递归的执行形式为递出去再归回来,这主要是因为执行时函数储存再内存的栈中。分治法的递归特点就是取代,小范围的取代大范围的,从而分而治之。应用在二叉树上,便是树上的每个非叶子节点都可以看作一个根节点。这也是本题的核心思想。

那么现在开始考虑这道题:我们已知的条件在细节中讲过,前序遍历结果的首位是树的根节点,既然根节点是已知的,根节点左右两子树也是已知的,那么我们是否可以把这颗树对半劈开,将左子树与右子树都看作一颗新树,那么结合递归思想,我们不断地为新树分配左右子树就可以了!话不多说,上代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 * int val;
 * TreeNode *left;
 * TreeNode *right;
 * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
private:
unordered_map<int,int> index;
public:

TreeNode* bulidOneTree(const vector<int>& preorder,const vector<int> inorder,int preorderLeft,int preorderRight,int inorderLeft,int inorderRight)
{
if(preorderLeft>preorderRight){   //递归不可少的结束条件,当树的节点用光时,程序自动结束。
return NULL;
}
int preorderRoot=preorderLeft;
int root=index[preorder[preorderRoot]];//确定根节点的位置。
TreeNode* treeRoot=new TreeNode(preorder[preorderRoot]);
int size=root-inorderLeft;

// 递归地构造左子树,并连接到根节点
    // 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
treeRoot->left=bulidOneTree(preorder,inorder,preorderLeft+1,preorderLeft+size,inorderLeft,root-1);

// 递归地构造右子树,并连接到根节点
    // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
treeRoot->right=bulidOneTree(preorder,inorder,preorderLeft+size+1,preorderRight,root+1,inorderRight);
return treeRoot;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n=preorder.size();
for(int i=0;i<n;i++){
index[inorder[i]]=i;
}
return bulidOneTree(preorder,inorder,0,n-1,0,n-1);
}
};