从前序与中序遍历序列构造二叉树
Leetcode105 https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
从后续与中序遍历序列构造二叉树
Leetcode106: https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
以105为例分析:本质利用分治的思想
- 前序中左起第一位1肯定是根结点,我们可以据此找到中序中根结点的位置rootin;
- 中序中根结点左边就是左子树结点,右边就是右子树结点,即[左子树结点,根结点,右子树结点], 我们就可以得出左子树结点个数为int left = rootin - leftin;
- 前序中结点分布应该是:[根结点,左子树结点,右子树结点];
- 根据前一步确定的左子树个数,可以确定前序中左子树结点和右子树结点的范围;
- 如果我们要前序遍历生成二叉树的话,下一层递归应该是:
左子树:root->left = pre_order(前序左子树范围,中序左子树范围,前序序列,中序序列);;
右子树:root->right = pre_order(前序右子树范围,中序右子树范围,前序序列,中序序列);。 - 每一层递归都要返回当前根结点root;
图示:
- 递归版本:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
TreeNode root=find(0,preorder.length-1,0,inorder.length-1,preorder,inorder);
return root;
}
public TreeNode find(int pre_left,int pre_right,int in_left,int in_right, int[] preorder,int[] inorder){
//终止条件,前序数组大小为空
if(pre_right<pre_left) return null;
TreeNode root=new TreeNode(preorder[pre_left]);
int index=0;
//寻找根结点在中序数组的位置,这里可以用hashmap优化,不用每次遍历
for(int i=in_left;i<=in_right;i++){
if(inorder[i]==root.val){
index=i;
break;
}
}
int len=index-in_left;
//构造左子树
root.left=find(pre_left+1,pre_left+len,in_left,index-1,preorder,inorder);
//构造右子树
root.right=find(pre_left+len+1,pre_right,index+1,in_right,preorder,inorder);
return root;
}
}
迭代版本:一般递归可利用栈实现迭代
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0) {
return null;
}
Stack<TreeNode> roots = new Stack<TreeNode>();
int pre = 0;
int in = 0;
//先序遍历第一个值作为根节点
TreeNode curRoot = new TreeNode(preorder[pre]);
TreeNode root = curRoot;
roots.push(curRoot);
pre++;
//遍历前序遍历的数组
while (pre < preorder.length) {
//出现了当前节点的值和中序遍历数组的值相等,寻找是谁的右子树
if (curRoot.val == inorder[in]) {
//每次进行出栈,实现倒着遍历
while (!roots.isEmpty() && roots.peek().val == inorder[in]) {
curRoot = roots.peek();
roots.pop();
in++;
}
//设为当前的右孩子
curRoot.right = new TreeNode(preorder[pre]);
//更新 curRoot
curRoot = curRoot.right;
roots.push(curRoot);
pre++;
} else {
//否则的话就一直作为左子树
curRoot.left = new TreeNode(preorder[pre]);
curRoot = curRoot.left;
roots.push(curRoot);
pre++;
}
}
return root;
}