先序+中序解法:
[1,2,3,4,5,6,7] //先序
[3,2,4,1,6,5,7] //中序
思路+步骤:
一、以先序第一个值1建立根节点,它是整棵树的根。
中序下标index的左边都是左子树:n个元素,右边都是右子树
中序下标index左边有n个元素,先序就该在原来的基础上向右偏移n个元素求得左子树的上限:pre_left + n
即左子树下标范围为[pre_left + 1, pre_left + n],右子树下标范围为[pre_left + n + 1, size - 1]
n = index - vin_pre //出界index - 入界vin_pre,即中序左子树有多少个元素
三、给根的左节点结上左子树,即递归左子树范围。
四、给根的右节点结上左子树,即递归右子树范围。
五、当然,最后要在开始的地方加上递归终止条件:if(pre_left > pre_right) return NULL;
C++代码:
class Solution { public: TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { return Rebuild(pre, 0, pre.size() - 1, vin, 0, vin.size() - 1); } //常引用减少复制 TreeNode* Rebuild(const vector<int>& pre, int pre_left, int pre_right, const vector<int>& vin, int vin_left, int vin_right){ //递归出口 if(pre_left > pre_right) return NULL; //进来就以先序第一个值创建节点 TreeNode* root =new TreeNode(pre[pre_left]); //找到先序第一个值在中序中的位置 int index_pre_in_vin; for(int i = vin_left; i <= vin_right; i++){ if(root->val == vin[i]){ index_pre_in_vin = i; break; } } //先序的左子树,和中序左子数数量是一样的,中序index左边有多少个元素,中序就应该向右偏移这么多。shift表示偏移。//右子树同理 int shift = index_pre_in_vin - vin_left; //递归结左子树 root->left = Rebuild(pre, pre_left + 1, pre_left + shift, vin, vin_left, index_pre_in_vin - 1); //递归结右子树 root->right = Rebuild(pre, pre_left + shift + 1, pre_right, vin, index_pre_in_vin + 1, vin_right); return root; } };
那么问题来了,怎么从中序、后序新建?
那么问题来了,怎么从中序、后序新建?
后序和先序是反的
先序:根左右,
后序:左右根。
思路1:
从后面向前做,包括:实参递归区间、建立根节点从右1建立、递归出口。
思路2:
后序和先序是反的
先序:根左右,
后序:左右根。
思路1:
从后面向前做,包括:实参递归区间、建立根节点从右1建立、递归出口。
思路2:
先中后序:根左右、左根右、左右根,,,,从左向右看和从右向左看是否是对称的?
利用栈将后序:左右根,转换为:根右左
利用栈将中序:左根右,转换为:右根左
利用栈将中序:左根右,转换为:右根左
看起来很像先序+中序了
只要创建时,先建立右子树,再建立左子树即可