題目
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。
例如,給出
前序遍歷 preorder = [3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:
3
/ \
9 20
/ \
15 7
限制:
0 <= 節點個數 <= 5000
解題思路
- 二叉樹的特點是什麼?
- 每個節點最多有兩棵子樹,所以二叉樹中不存在度大於2的節點。也可以沒有左子樹和右子樹。
-
- 根據便利的特點來進行重建
- 前序遍歷: 二叉樹爲空,則空操作返回,否則訪問根節點,然後前序遍歷左子樹,再前序遍歷右子樹。這塊就得注意了這就是插入點。
- 中序便利: 若樹爲空,則空操作返回,否則從根節點開始,中序遍歷根節點的左子樹,然後訪問根節點,然後訪問右子樹。
- 通過回想這個兩個遍歷的特點,那開始重建
- 從中序便利中我們可以判斷出根節點是哪一個,那就是前序遍歷的preorder[0].
- 我們知道了根節點,哪我們可以根據中續遍歷,就可以得出左子樹和右子樹。有哪些元素。
- 由於樹中的節點數量與遍歷方式無關,通過中序遍歷得知左子樹和右子樹的節點數量之後,可以根據節點數量得到前序遍歷中的左子樹和右子樹的分界,因此可以進一步得到左子樹和右子樹各自的前序遍歷和中序遍歷,可以通過遞歸的方式,重建左子樹和右子樹,然後重建整個二叉樹。
代碼
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;
}
}
總結
- 剛開始做這道題真的沒有思路,於是就看一邊答案,然後嘗試自己慢慢去寫,然後幾經調試。就跑出來了。
- 核心思想就是中序遍歷和前序遍歷的算法。
- 還有就是理解左子樹和右子樹的便利過程
參考
- https://blog.csdn.net/My_Jobs/article/details/43451187
- https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/