剑指Offer面试题七重建二叉树

重建二叉树java实现

剑指Offer面试题——七
题目描述:输入某个二叉树的前序遍历和中序遍历结果,重建该二叉树.。例如输入前序遍历[1,2,4,7,3,5,6,8] 和中序遍历[4,7,2,1,5,3,8,6]则重建如下图的二叉树

						  1
					        /   \
					       2     3
					     /      /  \
					    4      5    6
					    \          /
					     7        8			

1.思路图解

首先我们来看一下二叉树的遍历,所有前序遍历的第一个元素,一定是该二叉树的根节点。但是在中序遍历中根节点是在中间的,所以根据这两个特点,可以在中序遍历的数组中扫描,直到找到前序遍历中的根节点,这样就可以将中序遍历的数组分为三个部分。

如上图所示,前序遍历中第一个数1就是根节点,然后再中序遍历中扫描直到找到1为止,根据中序遍历(左根右)的特点,1前面的三个数[2,4,7] 就是左子树的节点的值,1后面的四个数[5,3,8,6]就是右子树节点的值

这时就找到了第一个根节点1

				                1
				              /   \
				        [2,4,7]  [5,3,8,6]

然后这时就以前序遍历片段[2,4,7] 和 中序遍历片段[4,7,2] 重复完成上述过程

				                1
				              /   \
				            2  [5,3,8,6]
				           /
			                [47]

2.代码实现

package datasturct;
public class ConstructCore {
    public static void main(String[] args) {
        int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
        int[] infix = {4, 7, 2, 1, 5, 3, 8, 6};
        TreeNode construct = construct(pre, infix);
        System.out.println(construct);

    }

    private static TreeNode construct(int[] pre, int[] infix) {
        if (pre == null || infix == null) {
            return null;
        }
        return constructTree(pre, infix, 0, pre.length - 1, 0, infix.length - 1);
    }

    /**
     * @param pre        前序便利数组
     * @param infix      中序遍历数组
     * @param preStart   递归时使用pre前序遍历数组开始的地方
     * @param preEnd     递归时使用pre前序遍历数组结束的地方
     * @param infixStart 递归时使用infix中序遍历数组开始的地方
     * @param infixEnd   递归时使用infix中序遍历数组开始的地方
     * @return 返回重建二叉树之后的根节点
     */
    public static TreeNode constructTree(int[] pre, int[] infix, int preStart, int preEnd, int infixStart, int infixEnd) {
        //前序遍历中,第一个值就为根节点
        int rootVal = pre[preStart];
        TreeNode root = new TreeNode(rootVal);
        if (preStart == preEnd) {
            if (infixStart == infixEnd && pre[preStart] == infix[infixStart]) {
                return root;
            }
        }
        int rootInfix = infixStart;
        //通过while循环找到rootVal在中序遍历数组infix中的位置
        while (rootInfix <= infixEnd && infix[rootInfix] != rootVal) {
            rootInfix++;
        }

        //如果到最后还没有找到
        if (rootInfix == infixEnd && infix[rootInfix] != rootVal) {
            System.out.println("Invalid Input");
        }

        int leftLength = rootInfix - infixStart; //左子树长度 应该为 根节点索引 - 中序遍历数组开始的位置
        int leftPreEnd = preStart + leftLength; // 下一次向左递归 前序遍历数组结束的位置 应该为前序遍历数组开始的位置
        if (leftLength > 0) {
            //向左递归构建左子树
            root.setLeft(constructTree(pre, infix, preStart + 1, leftPreEnd, infixStart, rootInfix - 1));
        }
        if (leftLength < preEnd - preStart) {
            root.setRight(constructTree(pre, infix, leftPreEnd + 1, preEnd, rootInfix + 1, infixEnd));
        }
        return root;
    }
}

class TreeNode {
    private int value;
    private TreeNode left;
    private TreeNode right;

    public TreeNode(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public TreeNode getLeft() {
        return left;
    }

    public void setLeft(TreeNode left) {
        this.left = left;
    }

    public TreeNode getRight() {
        return right;
    }

    public void setRight(TreeNode right) {
        this.right = right;
    }
    @Override
    public String toString() {
        return "TreeNode{" +
                "value=" + value +
                '}';
    }
    public void preOrder() {
        System.out.println(this);
        if (this.left != null) {
            this.left.preOrder();
        }
        if (this.right != null) {
            this.right.preOrder();
        }
    }
    public void infixOrder() {

        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值