---------------2020.12.11二刷--------------
六级、LeetCode、操作系统、软件体系结构
难顶啊,实在难顶
---------------一刷----------------------
该来的二叉树还是会来,记得当初期末考就问中序和前序能不能确定一颗二叉树。
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
限制:
0 <= 节点个数 <= 5000
解法 递归
先知道如何通过前序和中序确认一颗二叉树。
二叉树的前序遍历顺序是:根节点、左子树、右子树,每个子树的遍历顺序同样满足前序遍历顺序。
二叉树的中序遍历顺序是:左子树、根节点、右子树,每个子树的遍历顺序同样满足中序遍历顺序。
所以可以得知步骤
1.通过前序遍历先得到根结点的值。
2.然后将根结点带入中序遍历划分出左右子树。
3.根据左右子树的长度以及区间可以在前序遍历数组中得到其划分以及各自的根结点。
4.然后在左右子树分别递归。
所以很明显需要建立一个map来存储中序遍历的各节点所在位置,以便查找前序的根结点值带入时可以找到下标。
/**
* 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 {
public:
vector<int> preorder;
unordered_map<int,int> index;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
this->preorder=preorder;//recur函数需要用到preorder
for(int i=0;i<inorder.size();i++)
{
index[inorder[i]]=i;//结点在中序遍历中的下标
}
return beAtree(0,0,inorder.size()-1);
}
TreeNode *beAtree(int Root,int l,int r)//l为树的左边界,r为树的右边界
{
if(l>r)
return nullptr;//空指针 也可以定义一个空指针后返回
TreeNode* node=new TreeNode(preorder[Root]);
int i=index[preorder[Root]];//根结点在中序遍历数组中的下标
node->left=beAtree(Root+1,l,i-1);//左子树
node->right=beAtree(Root+(i-l)+1,i+1,r);//右子树的根结点在前序列表中的位置为(根结点+左子树长度+1)
return node;
}
};
时间O(n) 空间O(n)
1.哈希表O(n)空间
2.树:最差情况下,树退化为链表,O(n) 额外空间;
最好情况下,树为满二叉树,O(logn) 额外空间。
做一些递归的题目还是不太懂,看了别人的思路以后打得出来,但是自己往往写不出来,还有递归中参数的传递比较灵活,比如这题就把中序遍历中左子树的下标带入到前序遍历的数组里使用用于计算左子树长度。思维能力需要进一步加强。