美文网首页程序员java程序员
【剑指offer-03】重建二叉树

【剑指offer-03】重建二叉树

作者: d8a905c8d814 | 来源:发表于2018-08-26 00:44 被阅读1次

问题描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

解题思路

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */


public class Solution {
    
    /**
    * 前提:树的每个节点的值不重复
    * 思路:
    * 利用递归的思想,为什么想到递归呢?
    * 
    * 前序数组的第一个是根节点,记为i,在中序数组中找到它,
    * 则中序数组中i的左边明显是根节点的“左子树的中序遍历”,长度记为r,
    * 
    * 而我们也可以找到“左子树的前序遍历”,
    * 这需要在前序数组中根节点右边开始算的r个元素为左子树的前序遍历
    * 
    * 接着,我们还可以寻找“右子树的中序遍历”,很明显,中序数组中i的右边就是
    * 剩下,我们寻找“右子树的前序遍历”,在前序数组中找,中序数组中i的右边的长度记为m,
    * 则前序数组中i的倒数m个元素就是我们要找的“右子树前序遍历”
    * 
    * 看完这些,你应该大概能理解,为什么用递归了,
    * 因为我们每次都是能很明确的从前序数组中找到树的根节点,
    * 根节点需要left指向左子树根,right需要指向右子树根,所以可以通过递归不断求根,直到没有子树,就构建完一棵二叉树。
    */
    
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        
       return reConstructBinaryTreeInterval(pre, 0, pre.length - 1, in, 0, in.length -1);
    }
    
    /**
    * 参数说明: 
    * pre 原本前序数组
    * preI 树的前序遍历在前序数组中的起始下标
    * preJ 树的前序遍历在前序数组中的结束下标
    * in 原本的中序数组
    * inI 树的中序遍历在中序数组的起始下标
    * inJ 树的中序遍历在中序数组的结束下标
    */
    private TreeNode reConstructBinaryTreeInterval(int[] pre, int preI, int preJ, 
             int[] in, int inI, int inJ) {
        // 结束条件,也就是没有子树的情况,返回null
        if(preI > preJ || inI > inJ) {
            return null;
        }
        
        // 构建根节点
        TreeNode head = new TreeNode(pre[preI]);
        
        // 在中序数组中找到根节点的位置
        int position = -1;
        for(int i = inI; i <= inJ; i++) {
            if(pre[preI] == in[i]) {
                position = i;
                break;
            }
        }
            
        // 计算出左子树有多少个节点,
        int r = position - inI;
        
        
        //递归构建左子树,需要在前序数组中找到左子树的前序序列范围--> preI + 1开始 到preI + r
        //和中序数组中找到左子树的中序遍历范围--> inI开始到position -1
        head.left = reConstructBinaryTreeInterval(pre, preI + 1, preI + r, in, inI, position - 1);
        
        //递归构建右子树,需要在前序数组中找到右子树的前序序列范围--> preI + r + 1开始,到preJ
        // 和中序数组中找到右子树的中序遍历范围--> position + 1 到 inJ
        head.right = reConstructBinaryTreeInterval(pre,preI + r + 1, preJ, in, position + 1, inJ);
        
        return head;
    }
}

根据上面利用前序数组和中序数组重建二叉树的思路,可以总结出根据后序-中序数组重建的过程,以及前序-后序数组重建过程。

后序-中序 重建

后序数组的特点是根节点就是数组的最后一个元素。

我们只要得到下面这些信息,就好办了

  • 得出左子树的后序序列在后序数组的下标范围
  • 得出左子树的中序序列在中序数组的下标范围
  • 得出右子树的后序序列在后序数组的下标范围
  • 得出右子树的中序序列在中序数组的下标范围

1. 得出左子树的中序序列在中序数组的下标范围

中序序列数组中根节点左边的就是是左子树的中序遍历序列。同时可以得出左子树的长度。

2. 得出左子树的后序序列在后序数组的下标范围

后序数组中前N个元素就是左子树的后序序列,而上面已经可以求得这个N,也就可以算出下标范围了。

3. 得出右子树的中序序列在中序数组中的下标范围

中序数组中根节点的右边就是右子树的中序遍历序列, 因而下标范围可求。

4. 得出右子树的后序序列在后序数组中的下标范围

后序数组中前N个元素是左子树的后序序列,而剩下下标为N开始的到后序数组末尾不包括末尾,就是要求的下标范围。

对比上面的代码,你很快就能写出中序-后序的构建过程。

前序-后序 重建

前序-后序重建其实并不一定能重建一棵二叉树,有时候前序和后序序列并不能唯一确定一棵二叉树。

比如:头节点 为1, 左孩子为2,无右孩子,这时前序遍历:【1,2】;后序遍历:【2,1】。另一种情况,头节点为1,右孩子为2,无左孩子,这时前序和后序也是【1,2】和【2,1】。

因此,仅根据前序和后序序列是无法重建一棵二叉树的。

相关文章

  • 【剑指offer-03】重建二叉树

    问题描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复...

  • LeetCode | 面试题07. 重建二叉树【剑指Offer】

    LeetCode 面试题07. 重建二叉树【剑指Offer】【Medium】【Python】【二叉树】【递归】 问...

  • 剑指Offer(四)

    剑指Offer(四) 重建二叉树 题目描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的...

  • 重建二叉树

    《剑指offer》面试题7:重建二叉树 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前...

  • 71.重建二叉树

    day18: 剑指 Offer 07. 重建二叉树[https://leetcode-cn.com/prob...

  • 剑指Offer 07. 重建二叉树

    剑指 Offer 07. 重建二叉树 题目传送门[https://leetcode-cn.com/problems...

  • 重建二叉树

    上牛客网做了一道剑指offer的算法题 重建二叉树 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设...

  • 剑指Offer--(5)重建二叉树

    title: 剑指Offer--(5)重建二叉树 categories: 算法与数据结构 tags: 数据结构 题...

  • 剑指offer第二版-7.重建二叉树

    本系列导航:剑指offer(第二版)java实现导航帖 面试题7:重建二叉树 题目要求:根据二叉树的前序遍历和中序...

  • go 重建二叉树

    这是剑指offer的一道题。 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍...

网友评论

    本文标题:【剑指offer-03】重建二叉树

    本文链接:https://www.haomeiwen.com/subject/ykuniftx.html