剑指offer 面试题6—重建二叉树

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

分析:

前序遍历的第一个节点时根,在中序中找到这个根节点,然后左边就是左子树,右边就是右子树,这样就可以递归。

用数组来记录,然后每次还重新弄数组,把左子树复制过来,右子树复制过来,递归。

public TreeNode constructionOfTree(int[] pre, int[] in) {
        if (pre == null || pre.length == 0 || in == null || in.length == 0) {
            return null;
        }

        if (pre.length == 1 && in.length == 1) {
            return new TreeNode(pre[0]);
        }

        int len = pre.length;
        int root = pre[0];
        TreeNode tree = new TreeNode(root);

        int del = -1;
        for (int i = 0; i < in.length; i++) {
            if (in[i] == root) {
                del = i;
                break;
            }
        }

        int right_length = in.length - del - 1;
        int[] left_pre = new int[del];
        int[] left_in = new int[del];
        int[] right_pre = new int[right_length];
        int[] right_in = new int[right_length];

        for (int i = 1; i < del + 1; i++) {
            left_pre[i - 1] = pre[i];
            left_in[i - 1] = in[i - 1];
        }

        for (int i = del + 1; i < pre.length; i++) {
            right_pre[i - del - 1] = pre[i];
            right_in[i - del - 1] = in[i];
        }

        tree.left = constructionOfTree(left_pre, left_in);
        tree.right = constructionOfTree(right_pre, right_in);

        return tree;
    }

下面这种我觉得好些,用记录长度的方式,不用重复建立数组。

/**
     *
     * @param preOrder 前序遍历数组
     * @param inOrder 中序遍历数组
     * @param length 数组长度
     * @return 根结点
     */
    public static BinaryTreeNode Construct(int[] preOrder, int[] inOrder,int length){
        if (preOrder == null || inOrder == null || length <= 0) {
            return null;
        }
        try {
            return ConstructCore(preOrder, 0, preOrder.length - 1, inOrder, 0,inOrder.length - 1);
        } catch (InvalidPutException e) {
            e.printStackTrace();
            return null;
        }
    }  

    /**
     *
     * @param PreOrder
     *            前序遍历序列
     * @param startPreIndex
     *            前序序列开始位置
     * @param endPreIndex
     *            前序序列结束位置
     * @param InOrder
     *            中序遍历序列
     * @param startInIndex
     *            中序序列开始位置
     * @param endInIndex
     *            中序序列结束位置
     * @return 根结点
     * @throws InvalidPutException
     */
    public static BinaryTreeNode ConstructCore(int[] preOrder,int startPreIndex, int endPreIndex,
            int[] inOrder,int startInIndex, int endInIndex) throws InvalidPutException {  

        int rootValue = preOrder[startPreIndex];
        System.out.println("rootValue = " + rootValue);
        BinaryTreeNode root = new BinaryTreeNode(rootValue);  

        // 只有一个元素
        if (startPreIndex == endPreIndex) {
            if (startInIndex == endInIndex
                    && preOrder[startPreIndex] == inOrder[startInIndex]) {
                System.out.println("only one element");
                return root;
            } else {
                throw new InvalidPutException();
            }
        }  

        // 在中序遍历中找到根结点的索引
        int rootInIndex = startInIndex;  

        while (rootInIndex <= endInIndex && inOrder[rootInIndex] != rootValue) {
            ++rootInIndex;
        }  

        if (rootInIndex == endInIndex && inOrder[rootInIndex] != rootValue) {
            throw new InvalidPutException();  

        }  

        int leftLength = rootInIndex - startInIndex;  

        int leftPreOrderEndIndex = startPreIndex + leftLength;  

        if (leftLength > 0) {
            // 构建左子树
            root.leftNode = ConstructCore(preOrder, startPreIndex + 1,
                    leftPreOrderEndIndex, inOrder, startInIndex,
                    rootInIndex - 1);
        }  

        if (leftLength < endPreIndex - startPreIndex) {
            // 右子树有元素,构建右子树
            root.rightNode = ConstructCore(preOrder, leftPreOrderEndIndex + 1,
                    endPreIndex, inOrder, rootInIndex + 1, endInIndex);
        }
        return root;
    }  

    static class InvalidPutException extends Exception {  

        private static final long serialVersionUID = 1L;  

    }  

    public static void printPreOrder(BinaryTreeNode root) {
        if (root == null) {
            return;
        } else {
            System.out.print(root.value + " ");
        }  

        if (root.leftNode != null) {
            printPreOrder(root.leftNode);
        }  

        if (root.rightNode != null) {
            printPreOrder(root.rightNode);
        }
    }  

    public static void main(String[] args) throws Exception{
        ConstructionOfTree test=new ConstructionOfTree();
        int[] preOrder={1,2,4,7,3,5,6,8};
        int[] inOrder={4,7,2,1,5,3,8,6};
        printPreOrder(test.Construct(preOrder, inOrder, preOrder.length));
    }  

BinaryTreeNode.java

public class BinaryTreeNode {
    public int value;
    public BinaryTreeNode leftNode;
    public BinaryTreeNode rightNode;

    public BinaryTreeNode() {

    }

    public BinaryTreeNode(int value) {
        this.value = value;
        this.leftNode = null;
        this.rightNode = null;
    }
}
时间: 2025-01-03 10:04:29

剑指offer 面试题6—重建二叉树的相关文章

剑指offer系列之四:重建二叉树

题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 在完成代码之前,我自己分析了一下如何根据前序遍历和中序遍历的结果构建一棵二叉树.首先,根据二叉树遍历的性质,由前序遍历的结果序列可知该二叉树的根节点是1,在根据中序遍历的结果可是根节点1的左子树包含的结点是4.7.2,右子树包含的节点是5.3.8.6.

剑指offer系列之十七:二叉树的镜像

题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ 11 9 7 5 仔细观察原二叉树与镜像二叉树,可以发现镜像二叉树实际上就是把每个节点的左右孩子结点进行了交换,比如在遍历到8这个节点时候,首先交换其左右孩子6和10,其对应的子树也应该进行交换.所以我们可以采用前序遍历的方法进行操作,每当遇到一个结点的时候,首先判断其是否有左右孩子(有其中之一即

剑指offer 面试题2—实现单例模式

终于把简直offer看完了一遍 所以第二遍我决定要美一个题自己去实现一遍,会加入自己的理解(但是不一定对哈) 题目:设计一个类,我们只能生成该类的一个实例. 饿汉试 package T2Singleton; /** * 饿汉式 * @author yxx * */ public class Singleton { //私有构造方法 private Singleton() {} private static Singleton singleton = new Singleton(); public

剑指offer系列之五十七:二叉树的下一个节点

题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 根据中序遍历的特点,要找到一个节点的下一个节点无非就是三种情况:1.有右子树,这时只需要把其右孩子作为下一个遍历的(并不是要找的)节点,然后沿着该节点的左子树(如果有的话)出发,直到遇到叶子节点,那么该叶子节点就是其下一个要找的节点:2.没有右子树,则判断该节点是否是其父节点的左孩子,如果是则其下一个要找的节点是其父节点:3.如果不是其父节点的左孩子,

剑指offer 面试题3—二维数组中找数

题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 基本思想: 首先选取数组中右上角的数字.如果等于要找的数字,结束.如果大于要找的数字,剔除这个数字所在的列:如果小于要找的数字,剔除这个数字所在的行. public static boolean find(int[][] array, int number) { if (array == null || array.len

剑指offer 面试题5—从尾到头打印链表

题目: 输入一个链表的头结点,从尾到头反过来打印出每个结点的值. 考虑用栈 public void invertedList1(ListNode head) { if (head == null) { return; } ListNode p = head; Stack<Integer> stack = new Stack<Integer>(); while (p != null) { stack.push(p.val); p = p.next; } while (!stack.i

剑指offer 面试题4—替换字符串中空格

题目: 实现一个函数,把字符串中的每个空格替换成"%20".加入输入"we are happy.",则输出"we%20are%20happy.". 它想说的思想: 如果是字符数组来存储的话,每次扫描遇到空格都会导致后面的字符向后移动,然后为了节省这么多移动的时间,就先统计空格的个数,然后数组整体扩容空格数乘以3的空间,把那里当作结束,再从尾到头遍历,找到空格就移,这样整体就只移过了一次.效率会高很多. 举一反三: 合并两个数组(包括字符串)时,如

剑指offer系列之六十一:二叉树搜索树的第k个节点

题目描述 给定一颗二叉搜索树,请找出其中的第k大的结点.例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4. 因为二叉搜索树是排序的,所以如果需要找出第k个节点只需要进行中序遍历就可以得到第k节点.不过中序遍历的结果就是排序的,所以实质上就是插入排序.可以利用一个集合,在遍历的过程中利用插入排序的算法就能得到第k个节点.下面是这种实现思路的实现代码(已被牛客AC): public class Solution { //采用非递归中序遍历的方式得到第k

[剑指offer]8.重建二叉树

题目 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列. 代码 /*--------------------------------------- * 日期:2015-07-20 * 作者:SJF0115 * 题目: 8.重建二叉树 * 结果:AC * 网址:http://www.nowcoder