【LeetCode】重建二叉樹day04

題目

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

 

例如,給出

前序遍歷 preorder = [3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:

    3
   / \
  9  20
    /  \
   15   7
 

限制:

0 <= 節點個數 <= 5000

解題思路

  1. 二叉樹的特點是什麼?
  • 每個節點最多有兩棵子樹,所以二叉樹中不存在度大於2的節點。也可以沒有左子樹和右子樹。
  1. 根據便利的特點來進行重建
  • 前序遍歷: 二叉樹爲空,則空操作返回,否則訪問根節點,然後前序遍歷左子樹,再前序遍歷右子樹。這塊就得注意了這就是插入點。
  • 中序便利: 若樹爲空,則空操作返回,否則從根節點開始,中序遍歷根節點的左子樹,然後訪問根節點,然後訪問右子樹。
  1. 通過回想這個兩個遍歷的特點,那開始重建
  2. 從中序便利中我們可以判斷出根節點是哪一個,那就是前序遍歷的preorder[0].
  3. 我們知道了根節點,哪我們可以根據中續遍歷,就可以得出左子樹和右子樹。有哪些元素。
  4. 由於樹中的節點數量與遍歷方式無關,通過中序遍歷得知左子樹和右子樹的節點數量之後,可以根據節點數量得到前序遍歷中的左子樹和右子樹的分界,因此可以進一步得到左子樹和右子樹各自的前序遍歷和中序遍歷,可以通過遞歸的方式,重建左子樹和右子樹,然後重建整個二叉樹。

代碼

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
    //如果前序遍歷數組爲空那這棵樹也是空的
        if(preorder == null ){
            return null ;
        }else{
        //先拿到中序便利的數量
            int length = inorder.length;
        //通過Map記錄中序遍歷的值,在後面可以根據根節點拿到左子樹和又字樹的元素
         Map<Integer,Integer> inorderMap = new HashMap<Integer,Integer>();
            for(int i = 0 ;i<length;i++){
                inorderMap.put(inorder[i],i);
            }
            // 構建一個樹根據前序遍歷和後續遍歷的數組
            //其實有人會問爲什麼要這樣寫這麼多參數。因爲我們要遞歸調用將其中的遍歷的數組切開,然後去便利左子樹右子樹。
          return  buildTree(preorder,0,length-1,inorder,0,length-1,inorderMap);
        }
    }
      public  TreeNode buildTree(int [] preorder,int preorderStart,int preorderEnd,int[] inorder,int inoderStart, int inorderEnd,Map<Integer,Integer> inorderMap){
        if(preorderStart>preorderEnd){
            return null;
        }
        // 拿到根節點
        int rootVal  = preorder[preorderStart];
        // 創建一顆有根節點的二叉樹
        TreeNode root = new TreeNode(rootVal);
        if(preorderStart == preorderEnd){
            return root;
        }else{
        拿到根節點在遍歷數組中的位置
            int rootIndex =  inorderMap.get(rootVal);
            // 左子樹的節點數量
           int leftNodes =  rootIndex - inoderStart; 右子樹節點的數量
           int  rightNodes = inorderEnd - rootIndex;
            構建左子樹
            TreeNode leftSubtree = buildTree(preorder, preorderStart + 1, preorderStart + leftNodes, inorder, inoderStart, rootIndex - 1, inorderMap);
            便利右子樹
            TreeNode rightSubtree = buildTree(preorder, preorderEnd - rightNodes + 1, preorderEnd, inorder, rootIndex + 1, inorderEnd, inorderMap);
            //將左子樹與右子樹拼起來
            root.left = leftSubtree;
            root.right = rightSubtree;
        }
        return  root;

    }



}

總結

  1. 剛開始做這道題真的沒有思路,於是就看一邊答案,然後嘗試自己慢慢去寫,然後幾經調試。就跑出來了。
  2. 核心思想就是中序遍歷和前序遍歷的算法。
  3. 還有就是理解左子樹和右子樹的便利過程

參考

  • https://blog.csdn.net/My_Jobs/article/details/43451187
  • https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章