图解算法——从前序与中序遍历数组结构中构造二叉树
题目来源
根据一棵树的前序遍历与中序遍历构造二叉树
注意:
你可以假设树中没有重复的元素。
示例1:
前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]
则返回的二叉树为:
3 / \ 9 20 / \ 15 7
输出即是:[3,9,20,null,null,15,7]
来源于leetcode105
作者:LeetCode-Solution 链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/cong-qian-xu-yu-zhong-xu-bian-li-xu-lie-gou-zao-9/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
预前知识:
先说点基础知识:
- 二叉树前序遍历的顺序为:
先遍历根节点;
随后递归地遍历左子树;
最后递归地遍历右子树。
- 二叉树中序遍历的顺序为:
先递归地遍历左子树;
随后遍历根节点;
最后递归地遍历右子树。
举个例子:
一个二叉树为:
1 / \ 2 3 \ / 4 5
前序: 1->2->4->3->5
中序: 2->4->1->5->3
解决思路
方法一:递归
因为,
对于任意一颗树而言,前序遍历的形式总是: [ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ] ;
即根节点总是前序遍历中的第一个节点。
而中序遍历的形式总是: [ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ] ;
所以,只要我们在中序序列中找到根节点的下标,那么,中序序列左侧的数据就是根节点的左子树,右侧就是根节点的右子树。
然后,左子树的长度就可以通过根节点下标减去中序序列的最左侧下标得到。
因为不管先序还是中序,遍历的树是同一个树,故左右子树也是一样的,即长度也是一样的,故可求得先序序列中,左子树结束的下标。所以,只要确定好左右子树的位置下标即可。
在此提出:
在中序序列中查找根节点值所对应的下标时,可以是遍历数组,但是每次查找都要遍历一次,时间复杂度是O(n)显然不怎么高效。
但我们知道有一种数据结构叫hashmap,它的查找时间复杂度是O(1),故可利用他。
//Java
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { private Map<Integer,Integer> map = new HashMap<>(); public TreeNode buildTree(int[] preorder, int[] inorder) { int n = preorder.length; for(int i = 0 ; i<n; i++) { map.put(inorder[i],i); } return mybuildtree(preorder,inorder,0,n-1,0,n-1); } public TreeNode mybuildtree(int[] preorder, int[] inorder,int preL, int preR, int inL,int inR) { if(preL>preR) return null; int preroot = preL; int inroot = map.get(preorder[preroot]); TreeNode root = new TreeNode(preorder[preroot]); int len = inroot - inL; root.left = mybuildtree(preorder,inorder,preL+1 ,preL+len,inL ,inroot-1); root.right = mybuildtree(preorder,inorder,preL+len+1,preR ,inroot+1,inR ); return root; } }
C++:
/** * 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> map; public: TreeNode* mybuildtree(vector<int>& preorder, vector<int>& inorder, int preL,int preR,int inL,int inR) { if(preL > preR) return NULL; int preroot = preL; int inroot = map[preorder[preroot]]; TreeNode* root = new TreeNode(preorder[preroot]); int len = inroot - inL; root->left = mybuildtree(preorder,inorder,preL+1 ,preL+len,inL ,inroot-1); root->right = mybuildtree(preorder,inorder,preL+len+1,preR ,inroot+1 ,inR); return root; } TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { int n = inorder.size(); for(int i = 0;i<n; i++){ map[inorder[i]] = i; } return mybuildtree(preorder,inorder,0,n-1,0,n-1); } };
Over。。。