【題解二連發】Construct Binary Tree from Inorder and Postorder Traversal & Construct Binary Tree from Preor

LeetCode 原題連接

題目大意

  1. 給定一棵二叉樹的中序遍歷和後序遍歷,求這棵二叉樹的結構。
  2. 給定一棵二叉樹的前序遍歷和中序遍歷,求這棵二叉樹的結構。

樣例

  1. Input: inorder = [9, 3, 15, 20, 7], postorder = [9, 15, 7, 20, 3]
    Output: [3, 9, 20, null, null, 15, 7]
  2. Input: preorder = [3, 9, 20, 15, 7], postorder = [9, 3, 15, 20, 7]
    Output: [3, 9, 20, null, null, 15, 7]

解題思路

這兩題的解題思路相似,主要應用了二叉樹的這樣一個結論:算法

對於任意一棵二叉樹:json

  • 其前序遍歷序列的第一個元素爲該樹的根
  • 其後序遍歷序列的最後一個元素爲該樹的根

而後對於一棵二叉樹的遍歷序列,其元素排布老是遵循以下規律:c#

  • 前序遍歷:[根元素, [左子樹元素], [右子樹元素]]
  • 中序遍歷:[[左子樹元素], 根元素, [右子樹元素]]
  • 後序遍歷:[[左子樹元素], [右子樹元素], 根元素]

有了以上結論,這兩題的思路就很明確了:先從前序(或後序)遍歷中找到根元素,而後將遍歷結果按照上面的元素分佈規律分紅三個部分,對於左子樹和右子樹,遞歸地調用該算法去構建,便可得出完整的結構。數組

根據以上思路,能夠寫出對數組進行分割的代碼,記錄以下:post

  • 前序遍歷:ui

    /// <summary>
    /// 把二叉樹的前序遍歷序列分拆成左右兩部分
    /// 左右兩部分中,如有一個部分不存在,則返回長度爲 0 的數組
    /// 
    /// 在調用該方法前,須要提早爲左右兩部分的數組分配空間(即須要左右子樹的序列大小)
    /// </summary>
    /// <param name="sourceArray">一個數組,表示二叉樹的前序遍歷序列</param>
    /// <param name="leftPart">一個數組,表示這棵樹的左子樹的前序遍歷序列</param>
    /// <param name="rightPart">一個數組,表示這棵樹的右子樹的前序遍歷序列</param>
    private void SplitArray(int[] sourceArray, int[] leftPart, int[] rightPart)
    {
        // 對於前序遍歷,各部分對應的下標範圍爲:
        //   - [0, 1):根節點
        //   - [1, 1 + leftPart.Length):左子樹的前序遍歷序列
        //   - [1 + leftPart.Length, sourceArray.Length):右子樹的遍歷序列
    
        // 複製左子樹內容
        Array.Copy(sourceArray, 1, leftPart, 0, leftPart.Length);
        // 複製右子樹內容
        Array.Copy(sourceArray, 1 + leftPart.Length, rightPart, 0, rightPart.Length);
    }
  • 中序遍歷:code

    /// <summary>
    /// 把二叉樹的中序遍歷序列分拆成左右兩部分
    /// 左右兩部分中,如有一個部分不存在,則返回長度爲 0 的數組
    /// </summary>
    /// <param name="sourceArray">一個數組,表示二叉樹的中序遍歷序列</param>
    /// <param name="splitIndex">這棵二叉樹的根節點,在中序遍歷序列中的下標</param>
    /// <param name="leftPart">輸出參數,表示這棵樹的左子樹的中序遍歷序列</param>
    /// <param name="rightPart">輸出參數,表示這棵樹的右子樹的中序遍歷序列</param>
    void SplitArray(int[] sourceArray, int splitIndex, out int[] leftPart, out int[] rightPart)
    {
        // 爲左右兩部分分配空間
        // 對於中序遍歷,各部分對應的下標範圍爲
        //   - [0, splitIndex):左子樹的中序遍歷序列
        //   - [splitIndex, splitIndex + 1):根節點
        //   - [splitIndex + 1, sourceArray.Length):右子樹的中序遍歷序列
        leftPart = new int[splitIndex];
        rightPart = new int[sourceArray.Length - (splitIndex + 1)];
    
        // 複製左子樹內容
        Array.Copy(sourceArray, leftPart, leftPart.Length);
    
        // 複製右子樹內容
        Array.Copy(sourceArray, splitIndex + 1, rightPart, 0, rightPart.Length);
    }
  • 後序遍歷:遞歸

    /// <summary>
    /// 把二叉樹的後序遍歷序列分拆成左右兩部分
    /// 左右兩部分中,如有一個部分不存在,則返回長度爲 0 的數組
    /// 
    /// 在調用該方法前,須要提早爲左右兩部分的數組分配空間(即須要左右子樹的序列大小)
    /// </summary>
    /// <param name="sourceArray">一個數組,表示二叉樹的後序遍歷序列</param>
    /// <param name="leftPart">一個數組,表示這棵樹的左子樹的後序遍歷序列</param>
    /// <param name="rightPart">一個數組,表示這棵樹的右子樹的後序遍歷序列</param>
    void SplitArray(int[] sourceArray, int[] leftPart, int[] rightPart)
    {
        // 對於後序遍歷,各部分對應的下標範圍爲:
        //   - [0, leftPart.Length):左子樹的後序遍歷
        //   - [leftPart.Length, leftPart.Length + rightPart.Length):右子樹的後序遍歷
        //   - [leftPart.Length + rightPart.Length, sourceArray.Length):根節點
    
        // 複製左子樹內容
        Array.Copy(sourceArray, leftPart, leftPart.Length);
        // 複製右子樹內容
        Array.Copy(sourceArray, leftPart.Length, rightPart, 0, rightPart.Length);
    }

Solution

  • Construct Binary Tree from Inorder and Postorder Traversal內存

    /// <summary>
    /// 根據二叉樹的中序遍歷序列和後序遍歷序列,構建這棵二叉樹
    /// </summary>
    /// <param name="inorder">一個數組,表示二叉樹的中序遍歷序列</param>
    /// <param name="postorder">一個數組,表示二叉樹的後序遍歷序列</param>
    /// <returns>構建出的二叉樹的根節點</returns>
    public TreeNode BuildTree(int[] inorder, int[] postorder)
    {
        // 遞歸終止條件:序列的長度爲 0,返回 null
        if (inorder.Length == 0 || postorder.Length == 0)
            return null;
        // 從後序遍歷序列中找到根節點的值
        int rootVal = postorder.Last();
        // 在中序遍歷序列中找到根節點對應的下標,以便分出左右部分
        int rootIndex = Array.IndexOf(inorder, rootVal);
    
        // 提早爲後序遍歷的兩部分分配內存空間
        int[] postorderLeft = new int[rootIndex - 0];
        int[] postorderRight = new int[inorder.Length - (rootIndex + 1)];
    
        // 創建根節點
        TreeNode root = new TreeNode(rootVal);
    
        // 拆分中序遍歷序列
        SplitArray(inorder, rootIndex, out int[] inorderLeft, out int[] inorderRight);
    
        // 拆分後序遍歷序列
        SplitArray(postorder, postorderLeft, postorderRight);
    
        // 遞歸地調用該方法以構建左右子樹
        root.left = BuildTree(inorderLeft, postorderLeft);
        root.right = BuildTree(inorderRight, postorderRight);
    
        return root;
    }
  • Construct Binary Tree from Preorder and Inorder Traversalleetcode

    /// <summary>
    /// 根據二叉樹的中序遍歷序列和前序遍歷序列,構建這棵二叉樹
    /// </summary>
    /// <param name="preorder">一個數組,表示二叉樹的前序遍歷序列</param>
    /// <param name="inorder">一個數組,表示二叉樹的中序遍歷序列</param>
    /// <returns>構建出的二叉樹的根節點</returns>
    public TreeNode BuildTree(int[] preorder, int[] inorder)
    {
        // 遞歸終止條件:序列的長度爲 0,返回 null
        if (inorder.Length == 0 || preorder.Length == 0)
            return null;
        // 從前序遍歷序列中找到根節點的值
        int rootVal = preorder[0];
        // 在中序遍歷序列中找到根節點對應的下標,以便分出左右部分
        int rootIndex = Array.IndexOf(inorder, rootVal);
    
        // 提早爲前序遍歷的兩部分分配內存空間
        int[] preorderLeft = new int[rootIndex - 0];
        int[] preorderRight = new int[inorder.Length - (rootIndex + 1)];
    
        // 創建根節點
        TreeNode root = new TreeNode(rootVal);
    
        // 拆分中序遍歷序列
        SplitArray(inorder, rootIndex, out int[] inorderLeft, out int[] inorderRight);
    
        // 拆分前序遍歷序列
        SplitArray(preorder, preorderLeft, preorderRight);
    
        // 遞歸地調用該方法以構建左右子樹
        root.left = BuildTree(preorderLeft, inorderLeft);
        root.right = BuildTree(preorderRight, inorderRight);
    
        return root;
    }
相關文章
相關標籤/搜索