该问题中,会给出二叉树的前序与中序的遍历序列(没有重复元素)preorder和inorder,还原二叉树。
递归版(哈希表):
前序序列第一个值一定是根节点的值; 根据得到的根节点,在中序序列中可以得到二叉树根的索引 index,index的左边的值的个数即二叉树左子树节点的个数,左闭右开区间为(0,index),index的右边的值的个数即二叉树右子树节点的个数,左闭右开区间为(index+1,inorder.length) 中序序列中的左子树区域(0,index)即前序序列中的(1,index+1),同理可得二叉树前序序列中的右子树区域/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int preIndex=0;
int[] preorder;
int[] inorder;
HashMap indexMap=new HashMap();
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder=preorder;
this.inorder=inorder;
int idx=0;
for(Integer val:inorder) indexMap.put(val,idx++);
return help(0,inorder.length);
}
public TreeNode help(int inLeft,int inRight){
//若左边界等于右边界,说明区域为空,也就是没有值需要被构造成节点了
if(inLeft==inRight)return null;
//根据前序序列的第一个节点构造二叉树的根节点
int rootVal=preorder[preIndex++];
TreeNode root=new TreeNode(rootVal);
//找出根节点在中序序列中的位置
int index=indexMap.get(rootVal);
//对左子树和右子树进行递归
root.left=help(inLeft,index);
root.right=help(index+1,inRight);
return root;
}
}
递归版(不使用额外空间,也无需每次查找根节点在中序序列中的位置):
class Solution {
int pre=0;
int in=0;
int[] preorder;
int[] inorder;
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder=preorder;
this.inorder=inorder;
//stop是右边界,初始化stop的值为Integer.MAX_VALUE+1,也就是说stop的初始值不会是序列中任意一个数
return help((long)Integer.MAX_VALUE+1);
}
private TreeNode help(long stop){
if(pre==preorder.length)return null;
//递归左边界一直是in,当in=stop时递归停止
if(inorder[in]==stop){
in++;
return null;
}
int rootVal=preorder[pre++];
TreeNode root=new TreeNode(rootVal);
//左子树递归将每次根节点的值赋予stop,stop的右边是左子树
root.left=help(rootVal);
//右子树的右边界就是整棵树的stop,也就是序列中不存在的初始值
root.right=help(stop);
return root;
}
}
非递归版(迭代,栈)
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length==0)return null;
Stack roots=new Stack();
int pre=0;
int in=0;
TreeNode currRoot=new TreeNode(preorder[pre++]);
TreeNode root=currRoot;
roots.push(currRoot);
while(pre<preorder.length){
if(currRoot.val==inorder[in]){
while(!roots.isEmpty()&&roots.peek().val==inorder[in]){
currRoot=roots.pop();
in++;
}
currRoot.right=new TreeNode(preorder[pre++]);
currRoot=currRoot.right;
roots.push(currRoot);
}
else{
currRoot.left=new TreeNode(preorder[pre++]);
currRoot=currRoot.left;
roots.push(currRoot);
}
}
return root;
}
}
根据先序遍历构造二叉搜索树
该问题中,会给出二叉树的前序序列(没有重复元素)preorder,要求返回二叉搜索树。
思考时一定要考虑到二叉搜索树的特性:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。若是有所遗忘可参考二叉搜索树百度百科
二叉搜索树的中序遍历序列是从小到大的已排序序列。根据给定的前序遍历序列,排序后可得到所求二叉搜索树的中序遍历序列,那么这个问题就是根据前序与中序遍历序列构造二叉树
递归版:
class Solution {
int pre=0;
int in=0;
int[] preorder;
int[] inorder;
public TreeNode bstFromPreorder(int[] preorder) {
this.preorder=preorder;
inorder=Arrays.copyOf(preorder, preorder.length);
Arrays.sort(inorder);
return buildTreeHelp((long)Integer.MAX_VALUE+1);
}
private TreeNode buildTreeHelp(long stop){
if(pre==preorder.length)return null;
if(inorder[in]==stop){
in++;
return null;
}
int rootVal=preorder[pre++];
TreeNode root=new TreeNode(rootVal);
root.left=buildTreeHelp(rootVal);
root.right=buildTreeHelp(stop);
return root;
}
}
非递归版:
class Solution {
public TreeNode bstFromPreorder(int[] preorder) {
int[] inorder=Arrays.copyOf(preorder, preorder.length);
Arrays.sort(inorder);
if(preorder.length==0)return null;
Stack roots=new Stack();
int pre=0;
int in=0;
TreeNode currRoot=new TreeNode(preorder[pre++]);
TreeNode root=currRoot;
roots.push(currRoot);
while(pre<preorder.length){
if(currRoot.val==inorder[in]){
while(!roots.isEmpty()&&roots.peek().val==inorder[in]){
currRoot=roots.pop();
in++;
}
currRoot.right=new TreeNode(preorder[pre++]);
currRoot=currRoot.right;
roots.push(currRoot);
}
else{
currRoot.left=new TreeNode(preorder[pre++]);
currRoot=currRoot.left;
roots.push(currRoot);
}
}
return root;
}
}
根据中序与后序遍历序列构造二叉树
该问题中,会给出二叉树的中序与后序的遍历序列(没有重复元素)inorder和postorder,还原二叉树。
这个问题也与根据前序与中序遍历序列构造二叉树相似,根据中序遍历序列确定左右子树区间,根据后序遍历序列确定根节点。
递归版:
class Solution {
int postIndex;
int[] postorder;
int[] inorder;
HashMap indexMap=new HashMap();
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.postorder = postorder;
this.inorder = inorder;
postIndex=postorder.length-1;
int idx=0;
for(Integer val:inorder)indexMap.put(val,idx++);
return help(0,inorder.length-1);
}
public TreeNode help(int inLeft,int inRight){
if(inLeft>inRight)return null;
int rootVal=postorder[postIndex--];
TreeNode root = new TreeNode(rootVal);
int index=indexMap.get(rootVal);
//因为是后序和中序,所以在这里先递归右子树
root.right=help(index+1,inRight);
root.left=help(inLeft,index-1);
return root;
}
}
非递归版(栈):
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (postorder.length == 0) {
return null;
}
Stack roots = new Stack();
int post = postorder.length - 1;
int in = inorder.length - 1;
TreeNode currRoot = new TreeNode(postorder[post--]);
TreeNode root = currRoot;
roots.push(currRoot);
while (post >= 0) {
if (currRoot.val == inorder[in]) {
while (!roots.isEmpty() && roots.peek().val == inorder[in]) {
currRoot = roots.peek();
roots.pop();
in--;
}
currRoot.left = new TreeNode(postorder[post--]);
currRoot = currRoot.left;
roots.push(currRoot);
} else {
currRoot.right = new TreeNode(postorder[post--]);
currRoot = currRoot.right;
roots.push(currRoot);
}
}
return root;
}
}
根据前序与后序遍历序列构造二叉树
该问题中,会给出二叉树的前序与后序的遍历序列(没有重复元素)preorder和postorder,还原二叉树。
递归版:
因为前序是根左右的结构,后序是左右根的结构,所以可以考虑先建完左子树再考虑建右子树的问题
class Solution {
int preIndex=0;
int postIndex=0;
public TreeNode constructFromPrePost(int[] pre, int[] post) {
TreeNode root = new TreeNode(pre[preIndex++]);
//建左子树
if(root.val!=post[postIndex])root.left=constructFromPrePost(pre,post);
//建右子树
if(root.val!=post[postIndex])root.right=constructFromPrePost(pre, post);
postIndex++;
return root;
}
}