vlambda博客
学习文章列表

从前序与中序遍历序列构造二叉树

来源:LeetCode:105

题目描述:


给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的先序遍历inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。


示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

  • 1 <= preorder.length <= 3000

  • inorder.length == preorder.length

  • -3000 <= preorder[i], inorder[i] <= 3000

  • preorderinorder无重复 元素

  • inorder 均出现在 preorder

  • preorder 保证 为二叉树的前序遍历序列

  • inorder 保证 为二叉树的中序遍历序列

解题思路:

1.了解先序遍历,中序遍历的含义:
先序遍历: 依次遍历 根节点->左节点->右节点
中序遍历: 依次遍历 左节点->根节点->右节点
2.我们可以发现,一棵树的节点遍历:
(1)先序遍历中的第一个数永远是(根节点),右边是(左子树)(右子树),但不知道分布位置(也就是各自的数量)。

(2)中序遍历中根节点永远将两边划分为(左子树),(右子树)。

(3)由此,我们可以在先序遍历中找到根节点的val,再去中序遍历中找到该val对应根节点的索引(因为题目告诉是一个不重复的二叉树),我们用哈希表来映射节点对应的val值。

(4)找到在中序遍历中的根节点的位置,我们再进行划分,就可以知道左子树节点的数量,然后就可以在先序遍历中划分左子树和右子树的位置。

(5)最后找到先序和中序各自的左子树,右子树数组中位置,我们让两个左右树新的数组对应 再次递归进行第(1)步,不停往复。(两个新的左子树遍历数组 进行递归,两个新的左右子树遍历数组 进行递归)

(6)直至左边索引大于右边索引,递归结束。

代码实现:

/**
* Definition for a binary tree node.
* public class TreeNode {
*     int val;
*     TreeNode left;
*     TreeNode right;
*     TreeNode() {}
*     TreeNode(int val) { this.val = val; }
*     TreeNode(int val, TreeNode left, TreeNode right) {
*         this.val = val;
*         this.left = left;
*         this.right = right;
*     }
* }
*/
class Solution {
   public TreeNode buildTree(int[] preorder, int[] inorder) {
       Map<Integer,Integer> map = new HashMap<>();
       int len1 = preorder.length;
       int len2 = inorder.length;
       //映射节点与索引的关系
       for(int i=0;i<len1;i++){
           map.put(inorder[i],i);
      }
       return buildTree(preorder ,0,len1-1,inorder,0,len2-1,map);

  }

   TreeNode buildTree(int[] preorder,int pre_l,int pre_r ,int[] inorder,int inor_l ,int inor_r,Map<Integer,Integer> map){
       //如果先序遍历数组左边边界大于右边,返回null
      if(pre_l>pre_r){
          return null;
      }
        //如果中序遍历数组左边边界大于右边,返回null
      if(inor_l>inor_r){
          return null;
      }
       //先序遍历的第一个数==每棵树的根节点
       int root_val = preorder[pre_l];
       TreeNode root = new TreeNode(root_val);
       //在hash获取中序遍历中的根节点的位置,目的:计算左右子树的节点数量,来划分新的子树,进行递归
       int inor_index = map.get(root_val);
       //左子树
       /*
       pre_l+1:先序遍历左子树的左边界
       pre_l+(inor_index - inor_l):先序遍历左子树的右边界
       inor_l:中序遍历左子树的左边界
       inor_index-1:中序遍历左子树的右边界
       */
       root.left = buildTree(preorder,pre_l+1,pre_l+(inor_index - inor_l),inorder,inor_l,inor_index-1,map);
       //右子树
       /*
       preorder,pre_l+(inor_index - inor_l)+1:先序遍历右子树的左边界
       pre_r:先序遍历右子树的右边界
       inor_index+1:中序遍历右子树的左边界
       inor_r:中序遍历右子树的右边界
       
       */
       root.right = buildTree(preorder,pre_l+(inor_index - inor_l)+1,pre_r,inorder,inor_index+1,inor_r,map);
       return root;
  }
}