代码随想录二刷 | 二叉树 | 从中序与后序遍历序列构造二叉树

代码随想录二刷 | 二叉树 | 从中序与后序遍历序列构造二叉树

  • 题目描述
  • 解题思路
  • 代码实现

题目描述

106.从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例 1:
代码随想录二刷 | 二叉树 | 从中序与后序遍历序列构造二叉树_第1张图片
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

示例 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

提示:

  • 1 <= inorder.length <= 3000
  • postorder.length == inorder.length
  • -3000 <= inorder[i], postorder[i] <= 3000
  • inorder 和 postorder 都由 不同 的值组成
  • postorder 中每一个值都在 inorder 中
  • inorder 保证是树的中序遍历
  • postorder 保证是树的后序遍历

解题思路

根据两个顺序构建二叉树,注意三个点:

  • 第一,前序遍历为中左右,中序遍历为左右中,后序遍历是左右中;
  • 第二,后序遍历的最后一个元素一定是根节点;
  • 第三,前序数组、中序数组、后序数组的大小是相等的。

找到根节点后再根据每个遍历的特点,就能在纸上很轻松地还原出二叉树。

这里使用递归一步一步拆分:

  • 第一步:如果数组大小为0,说明为空节点
    if (postorder.size() == 0) return NULL;
    
  • 第二步:如果不为空,那么取后序数组的最后一个节点为根节点
    int rootValue = postorder[postorder.size() - 1];
    TreeNode* root = new TreeNode(rootValue);
    // 如果root就是叶子节点,也就是说这是一个只有根节点的二叉树,直接返回root
    if (postorder.size() == 1) return root;
    
  • 第三步:找到根节点在中序数组的位置,作为拆分点
    int delimiterIndex;
    for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
    	if (inorder[delimiterIndex] == rootValue) break;
    }
    
  • 第四步:拆分中序数组,左边为中序左数组,右边为中序右数组,(中序遍历为左右中)
    // 左闭右开区间 [0, delimiterIndex)
    vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
    // [delimeterIndex, end)
    vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end())
    
  • 第五步:拆分后序数组,拆成后序左数组和后序右数组(后序遍历为左右中)
    // 因为后序数组没有很明显的拆分点,但它的长度是和中序数组相等的,对应的根节点的左右子树的长度也是相等的,所以可以根据中序左数组的大小作为拆分点来拆分,拆分成后序左数组和后序右数组。
    // 舍弃末尾元素,因为这个元素已经是根节点了,我们拆分出来的实际是根节点的左右子树,所以先去掉它
    postorder.resize(postorder.size() - 1);
    // 左闭右开,使用中序左数组的长度作为拆分点 [0, leftInorder.size())
    vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size())
    // [leftInorder.size(), end)
    vector<int> rightPostorder(postorder.begin() + leftInorder.size() + 1, postorder.end());
    
  • 第六步,递归处理左数组和有数组
    root->left = traversal(leftInorder, leftPostorder);
    root->left = traversal(rightInorder, rightPostorder);
    return root;
    

代码实现

class Solution {
private:
	TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
		// 空节点,返回NULL
		if (postorder.size() == 0) return NULL;

		// 后序数组的最后一个元素为根节点
		int rootValue = postorder.size() - 1;
		TreeNode* root = new TreeNode(rootValue); 
		
		// 根节点为叶子节点,返回root
		if (postorder.size() == 1) return root;
		
		// 找到中序遍数组的拆分点
		int delimiterIndex;
		for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
			if (inorder[delimiterIndex] == rootValue) break;
		}
		// 切割中序数组
		// [0, delimiterIndex)
		vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
		// [delimiterIndex + 1, end)
		vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
	
		// postorder 去掉末尾元素	
		postorder.resize(postorder.size() - 1);
		
		// 拆分后序数组
		// [0, leftInorder.size())
		vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
		// [leftInorder,size(), end)
		// 没有 + 1的原因是,虽然是左闭右开,但是已经将根节点剔除了
		vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
		
		// 递归左右数组
		root->left = traversal(leftInorder, leftPostorder);
		root->right = traversal(rightInorder, rightPostorder);

		return root;
	}
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
		if (inorder.size() == 0 || postorder.size() == 0) return NULL;
		return ttraversal(inorder, postorder);
    }
};

你可能感兴趣的:(代码随想录二刷,leetcode,算法,c++)