leetcode105/106-从前序与中序/中序与后序遍历中构造二叉树

从两种遍历结果构造二叉树

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

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

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

思路:

两道题目思路都是相同的,从前序/后序遍历的结果中可以率先确定root,然后在中序遍历的结果中找到root,对左右子树进行划分,整个代码用递归的方式构造出二叉树。

105代码:

class Solution {
   public TreeNode buildTree(int[] preorder, int[] inorder) {
        return bulid(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);//这个先写,你传入的参数肯定就是这几个
    }

    public TreeNode bulid(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd){
        //最后写递归出口 base case,很简单,就是两个数组之一越界就是出口(其实写1个也行,因为两个数组长度肯定相同的)
        if(preStart > preEnd || inStart > inEnd){
            return null;
        }

        /*先序遍历框架-根、左、右*/
        //1.先构造根节点的值,做根节点
        //2.递归构造左子树
        //3.递归构造右子树

        //1.很明显根节点的值由先序遍历数组的第一个值确定
        int rootVal = preorder[preStart];
        TreeNode root = new TreeNode(rootVal);
        //2.递归构造左子树
        // root.left = bulid(preorder, ?, ?, inorder, ?, ?);//?需要我们画图去求的,也就是左右子树的索引
        // root.right = bulid(preorder, ?, ?, inorder, ?, ?);//?需要我们画图去求的,也就是左右子树的索引
        //首先通过rootVal在inorder中的索引(index),然后就能够知道inorder中左子树和右子树的边界
        //可以改进的,一开始用hashMap把inorder的值和索引存好,到时候直接查就行。
        int index = -1;
        for(int i = inStart; i <= inEnd; i++){
            if(rootVal == inorder[i]){
                index = i;
                break;
            }
        }
        //找到了index,确定inorder中左右子树的边界
        // root.left = bulid(preorder, ?, ?, inorder, inStart, index - 1);//确定inorder中左子树的边界
        // root.right = bulid(preorder, ?, ?, inorder, index + 1, inEnd);//确定inorder中右子树的边界
        //通过inorder中左子树节点的数目来确定preorder中左右子树的边界
        int nums_of_left_tree = index - inStart; 
        // root.left = bulid(preorder, preStart + 1, preStart + nums_of_left_tree, inorder, ?, ?);//确定preorder中左子树的边界
        // root.right = bulid(preorder, preStart + nums_of_left_tree + 1, preEnd, inorder, ?, ?);//确定preorder中右子树的边界
        //最终确认好preorder和inorder中的左右子树边界
        root.left = bulid(preorder, preStart + 1, preStart + nums_of_left_tree, inorder, inStart, index - 1);
        root.right = bulid(preorder, preStart + nums_of_left_tree + 1, preEnd, inorder, index + 1, inEnd);
        return root;
    }
}

106代码:

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        int len=inorder.length;
        return buildTree(inorder,0,len-1,postorder,0,len-1);
    }
    public TreeNode buildTree(int[] inorder,int inStart,int inEnd,int[] postorder,int postStart,int postEnd){
        if(inStart>inEnd||postStart>postEnd){
            return null;
        }

        //后序遍历的最后一个节点是根节点
        int root = postorder[postEnd];
        TreeNode node =new TreeNode(root);

        //通过后序遍历中确定的根节点在中序遍历中确定左右子树的范围
        int index=0;
        for(int i=inStart;i<=inEnd;i++){
            if(inorder[i]==root){
                index=i;
                break;
            }
        }
        node.left=buildTree(inorder,inStart,index-1,postorder,postStart,postStart+index-inStart-1);
        node.right=buildTree(inorder,index+1,inEnd,postorder,postEnd-inEnd+index,postEnd-1);
        return node;
    }
}

你可能感兴趣的:(leetcode105/106-从前序与中序/中序与后序遍历中构造二叉树)