LeetCode——105.從前序與中序遍歷序列構造二叉樹

LeetCode——105.從前序與中序遍歷序列構造二叉樹

題目

105.從前序與中序遍歷序列構造二叉樹
根據一棵樹的前序遍歷與中序遍歷構造二叉樹。

注意:
你可以假設樹中沒有重複的元素。

例如,給出

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

返回如下的二叉樹:

    3
   / \
  9  20
    /  \
   15   7

解析

圖來自LeetCode官方題解
在這裏插入圖片描述
在這裏插入圖片描述

遞歸創建。思路如上圖:
通過前序數組來確定根節點,然後在中序數組中找到根節點,中序數組通過根節點的下標就可以確定左子樹和右子樹和下標範圍,然後遞歸調用就可以了。前序數組中左子樹和右子樹的下標範圍公式自己算一下就明白了。

代碼

/**
 * 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) {
        //判斷輸入數據是否正確,可以不寫
        int preorderLen = preorder.length; //獲得兩個數組的長度
        int inorderLen = inorder.length;
        if (preorderLen != inorderLen){ //判斷長度是否相等
            throw new RuntimeException("Incorrect input data!");
        }

        //創建二叉樹
        return creatTree(preorder, inorder,0, preorder.length-1, 0, inorder.length-1);
    }

    /**
     *
     * @param preorder  前序遍歷的數組
     * @param inorder   中序遍歷的數組
     * @param preLeft   要使用的前序遍歷數組的起始下標
     * @param preRight  要使用的前序遍歷數組的結束下標
     * @param inLeft    要使用的中序遍歷數組的起始下標
     * @param inRight   要使用的中序遍歷數組的結束下標
     * @return
     */
    private TreeNode creatTree(int[] preorder, int[] inorder, int preLeft, int preRight, int inLeft, int inRight) {
        //遞歸終止條件
        if (preLeft > preRight || inLeft > inRight){
            return null;
        }

        //遞歸體
        int pIndex = 0; //存放中序數組中根節點的下標
        // 前序數組中的第一個節點就是根節點
        int rootVal = preorder[preLeft]; //獲取根節點的值
        // 先把根節點建立出來
        TreeNode root = new TreeNode(rootVal);
        // 在中序數組中定位根節點下標(這一步可以用Map優化)
        for (int i = inLeft; i <= inRight; i++) {
            if (rootVal == inorder[i]){ //如果找到根節點
                pIndex = i; //記錄中序數組中根節點的下標
                break;
            }
        }

        //這裏傳入新的下標的公式,可以自己在草稿紙上算一下。
        //前序和中序數組的左子樹區間
        root.left = creatTree(preorder, inorder, preLeft+1, pIndex-inLeft+preLeft, inLeft, pIndex-1);
        //前序和中序數組的右子樹區間
        root.right = creatTree(preorder, inorder, pIndex-inLeft+preLeft+1, preRight, pIndex+1, inRight);

        return root;
    }
    
}

在這裏插入圖片描述

使用HashMap進行優化

/**
 * 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) {
        //判斷輸入數據是否正確,可以不寫
        int preorderLen = preorder.length; //獲得兩個數組的長度
        int inorderLen = inorder.length;
        if (preorderLen != inorderLen){ //判斷長度是否相等
            throw new RuntimeException("Incorrect input data!");
        }

        //使用map存儲中序數組,幫助我們快速定位根節點
        Map<Integer,Integer> map = new HashMap<>(preorder.length);
        for (int i = 0; i < preorder.length; i++) {
            map.put(inorder[i],i); //注意這裏是把中序數組中的值當做鍵,下標當做值,便於查找
        }

        //創建二叉樹
        return creatTree(preorder, map,0, preorder.length-1, 0, inorder.length-1);
    }

    /**
     *
     * @param preorder  前序遍歷的數組
     * @param map       存放中序遍歷數組的map
     * @param preLeft   要使用的前序遍歷數組的起始下標
     * @param preRight  要使用的前序遍歷數組的結束下標
     * @param inLeft    要使用的中序遍歷數組的起始下標
     * @param inRight   要使用的中序遍歷數組的結束下標
     * @return
     */
    private TreeNode creatTree(int[] preorder, Map<Integer,Integer> map, int preLeft, int preRight, int inLeft, int inRight) {
        //遞歸終止條件
        if (preLeft > preRight || inLeft > inRight){
            return null;
        }

        //遞歸體
        // 前序數組中的第一個節點就是根節點
        int rootVal = preorder[preLeft]; //獲取根節點的值
        // 先把根節點建立出來
        TreeNode root = new TreeNode(rootVal);
        // 在中序數組中定位根節點下標
        int pIndex = map.get(rootVal);

        //這裏傳入新的下標的公式,可以自己在草稿紙上算一下。
        //前序和中序數組的左子樹區間
        root.left = creatTree(preorder, map, preLeft+1, pIndex-inLeft+preLeft, inLeft, pIndex-1);
        //前序和中序數組的右子樹區間
        root.right = creatTree(preorder, map, pIndex-inLeft+preLeft+1, preRight, pIndex+1, inRight);

        return root;
    }

}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章