LeetCode——105.从前序与中序遍历序列构造二叉树

LeetCode——105.从前序与中序遍历序列构造二叉树

题目

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

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

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

解析

图来自LeetCode官方题解
在这里插入图片描述
在这里插入图片描述

递归创建。思路如上图:
通过前序数组来确定根节点,然后在中序数组中找到根节点,中序数组通过根节点的下标就可以确定左子树和右子树和下标范围,然后递归调用就可以了。前序数组中左子树和右子树的下标范围公式自己算一下就明白了。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //判断输入数据是否正确,可以不写
        int preorderLen = preorder.length; //获得两个数组的长度
        int inorderLen = inorder.length;
        if (preorderLen != inorderLen){ //判断长度是否相等
            throw new RuntimeException("Incorrect input data!");
        }

        //创建二叉树
        return creatTree(preorder, inorder,0, preorder.length-1, 0, inorder.length-1);
    }

    /**
     *
     * @param preorder  前序遍历的数组
     * @param inorder   中序遍历的数组
     * @param preLeft   要使用的前序遍历数组的起始下标
     * @param preRight  要使用的前序遍历数组的结束下标
     * @param inLeft    要使用的中序遍历数组的起始下标
     * @param inRight   要使用的中序遍历数组的结束下标
     * @return
     */
    private TreeNode creatTree(int[] preorder, int[] inorder, int preLeft, int preRight, int inLeft, int inRight) {
        //递归终止条件
        if (preLeft > preRight || inLeft > inRight){
            return null;
        }

        //递归体
        int pIndex = 0; //存放中序数组中根节点的下标
        // 前序数组中的第一个节点就是根节点
        int rootVal = preorder[preLeft]; //获取根节点的值
        // 先把根节点建立出来
        TreeNode root = new TreeNode(rootVal);
        // 在中序数组中定位根节点下标(这一步可以用Map优化)
        for (int i = inLeft; i <= inRight; i++) {
            if (rootVal == inorder[i]){ //如果找到根节点
                pIndex = i; //记录中序数组中根节点的下标
                break;
            }
        }

        //这里传入新的下标的公式,可以自己在草稿纸上算一下。
        //前序和中序数组的左子树区间
        root.left = creatTree(preorder, inorder, preLeft+1, pIndex-inLeft+preLeft, inLeft, pIndex-1);
        //前序和中序数组的右子树区间
        root.right = creatTree(preorder, inorder, pIndex-inLeft+preLeft+1, preRight, pIndex+1, inRight);

        return root;
    }
    
}

在这里插入图片描述

使用HashMap进行优化

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //判断输入数据是否正确,可以不写
        int preorderLen = preorder.length; //获得两个数组的长度
        int inorderLen = inorder.length;
        if (preorderLen != inorderLen){ //判断长度是否相等
            throw new RuntimeException("Incorrect input data!");
        }

        //使用map存储中序数组,帮助我们快速定位根节点
        Map<Integer,Integer> map = new HashMap<>(preorder.length);
        for (int i = 0; i < preorder.length; i++) {
            map.put(inorder[i],i); //注意这里是把中序数组中的值当做键,下标当做值,便于查找
        }

        //创建二叉树
        return creatTree(preorder, map,0, preorder.length-1, 0, inorder.length-1);
    }

    /**
     *
     * @param preorder  前序遍历的数组
     * @param map       存放中序遍历数组的map
     * @param preLeft   要使用的前序遍历数组的起始下标
     * @param preRight  要使用的前序遍历数组的结束下标
     * @param inLeft    要使用的中序遍历数组的起始下标
     * @param inRight   要使用的中序遍历数组的结束下标
     * @return
     */
    private TreeNode creatTree(int[] preorder, Map<Integer,Integer> map, int preLeft, int preRight, int inLeft, int inRight) {
        //递归终止条件
        if (preLeft > preRight || inLeft > inRight){
            return null;
        }

        //递归体
        // 前序数组中的第一个节点就是根节点
        int rootVal = preorder[preLeft]; //获取根节点的值
        // 先把根节点建立出来
        TreeNode root = new TreeNode(rootVal);
        // 在中序数组中定位根节点下标
        int pIndex = map.get(rootVal);

        //这里传入新的下标的公式,可以自己在草稿纸上算一下。
        //前序和中序数组的左子树区间
        root.left = creatTree(preorder, map, preLeft+1, pIndex-inLeft+preLeft, inLeft, pIndex-1);
        //前序和中序数组的右子树区间
        root.right = creatTree(preorder, map, pIndex-inLeft+preLeft+1, preRight, pIndex+1, inRight);

        return root;
    }

}

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章