連結: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;
}
}