leetcode 105. 从前序与中序遍历序列构造二叉树

大耗子 2021年02月18日 18次浏览

从前序与中序遍历序列构造二叉树

105. 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

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

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

解题思路

通过递归的方法,不断缩小树的范围,将树拆解到叶子,再将叶子赋值到左或者右子树上即可。(第一次写题解,多多谅解,哈哈)

前序遍历

由性质可以得到数组最左边一定是右边数据的父节点。

中序遍历

通过前序遍历得到父亲节点后,找到中序数组中节点的位置,该位置的左边数据都是左子树,右边数据是右子树。通过位置的计算就可以得到该父节点的左子树个数和右子树个数。

代码

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

map<int, int> mapIn;

class Solution {
public:
	TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
		if (!preorder.size() || !inorder.size() ||preorder.size() != inorder.size()) 
			return NULL;
		// 将中序遍历的数据的下标放在map中,方便查找
		for (int i = 0; i < inorder.size(); i++){
			mapIn[inorder[i]] = i;
		}
		return buildTreeCore(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1);
	}

	TreeNode* buildTreeCore(vector<int>& preorder, vector<int>& inorder,
		int preBegin, int preEnd, int inBegin, int inEnd) {
		// 递归退出条件
		if (preBegin > preEnd) return NULL;
		// 申请节点
		TreeNode * root = new TreeNode(preorder[preBegin]);
		// 只有一个节点(或者叶子结点)
		if (preBegin == preEnd) return root;

		// 计算左子树的长度
		int leftLen = mapIn[root->val] - inBegin;
		int leftEndIndex = preBegin + leftLen;
		// 有左子树先构建左子树
		if (leftLen > 0) {
			root->left = buildTreeCore(preorder, inorder, preBegin + 1, preBegin + leftLen, inBegin, inBegin + leftLen - 1);
		}
		// 构建右子树
		if(preEnd - leftEndIndex > 0){
			root->right = buildTreeCore(preorder, inorder, preBegin + leftLen + 1, preEnd, mapIn[root->val] + 1, inEnd);
		}

		return root;
	}
};