劍指 Offer 07. 重建二叉樹

CodeTiger發表於2021-06-14

連結:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/

標籤:樹、遞迴

題目

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。

例如,給出

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

返回如下的二叉樹:

    3
   / \
  9  20
    /  \
   15   7

限制:

0 <= 節點個數 <= 5000

分析

知道一棵樹的先序遍歷和中序遍歷,可以還原一顆二叉樹。知道一棵樹的先序遍歷和後續遍歷,也可以還原一顆二叉樹。但如果知道中序遍歷和後序遍歷,是無法還原二叉樹的,因為無法區分左右子樹。

對於此題,假設有一顆二叉樹的先序序列[3, 9, 6, 8, 20, 15, 7],中序序列[6, 9, 8, 3, 15, 20, 7],樹是下面這個樣子的

在這裡插入圖片描述

我們還原的步驟如下:

(1)根據先序遍歷節點3,是樹的根節點,然後在中序序列裡查詢3的位置,3左邊的節點[6, 9 ,8]組成樹的左子樹,3右邊的節點[15, 20, 7]組成樹的右子樹。

(2)對左子樹重複步驟(1)

(3)對右子樹重複步驟(1)

此題的難點在於如何確定左右子樹的根節點。對於左子樹,preorder[i +1]就是根節點,對於右子樹,因為先序遍歷是先走根節點再走左子樹,那麼只需要知道當前左子樹有幾個節點,就可以知道右子樹的根節點了。

編碼

/**
 * 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) {
        return createTree(0, 0, inorder.length - 1, preorder, inorder);
    }

    private TreeNode createTree(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder) {
        if (preStart >= preorder.length || inStart > inEnd) {
            return null;
        }

        // 根節點
        TreeNode root = new TreeNode(preorder[preStart]);
        int rootIndex = 0;
        // 查詢根節點在中序陣列裡的位置,拆分左右子樹
        for (int i = 0; i < inorder.length; i++) {
            if (preorder[preStart] == inorder[i]) {
                rootIndex = i;
                break;
            }
        }

        // 建立左子樹
        root.left = createTree(preStart + 1, inStart, rootIndex - 1, preorder, inorder);
        // 建立右子樹,rootIndex - inStart即當前左子樹的節點數量
        root.right = createTree(preStart + 1 + rootIndex - inStart, rootIndex + 1, inEnd, preorder, inorder);
        return root;
    }
}

在這裡插入圖片描述

相關文章