非傳統公司拼多多,與黃崢等人捐贈成立的繁星基金會
阿新 • • 發佈:2021-05-19
連結: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; } }