Input: inorder = [9, 3, 15, 20, 7], postorder = [9, 15, 7, 20, 3] Output: [3, 9, 20, null, null, 15, 7]
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); }
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; }