LeetCode——105.從前序與中序遍歷序列構造二叉樹
題目
105.從前序與中序遍歷序列構造二叉樹
根據一棵樹的前序遍歷與中序遍歷構造二叉樹。
注意:
你可以假設樹中沒有重複的元素。
例如,給出
前序遍歷 preorder = [3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:
3
/ \
9 20
/ \
15 7
解析
圖來自LeetCode官方題解
遞歸創建。思路如上圖:
通過前序數組來確定根節點,然後在中序數組中找到根節點,中序數組通過根節點的下標就可以確定左子樹和右子樹和下標範圍,然後遞歸調用就可以了。前序數組中左子樹和右子樹的下標範圍公式自己算一下就明白了。
代碼
/**
* 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) {
//判斷輸入數據是否正確,可以不寫
int preorderLen = preorder.length; //獲得兩個數組的長度
int inorderLen = inorder.length;
if (preorderLen != inorderLen){ //判斷長度是否相等
throw new RuntimeException("Incorrect input data!");
}
//創建二叉樹
return creatTree(preorder, inorder,0, preorder.length-1, 0, inorder.length-1);
}
/**
*
* @param preorder 前序遍歷的數組
* @param inorder 中序遍歷的數組
* @param preLeft 要使用的前序遍歷數組的起始下標
* @param preRight 要使用的前序遍歷數組的結束下標
* @param inLeft 要使用的中序遍歷數組的起始下標
* @param inRight 要使用的中序遍歷數組的結束下標
* @return
*/
private TreeNode creatTree(int[] preorder, int[] inorder, int preLeft, int preRight, int inLeft, int inRight) {
//遞歸終止條件
if (preLeft > preRight || inLeft > inRight){
return null;
}
//遞歸體
int pIndex = 0; //存放中序數組中根節點的下標
// 前序數組中的第一個節點就是根節點
int rootVal = preorder[preLeft]; //獲取根節點的值
// 先把根節點建立出來
TreeNode root = new TreeNode(rootVal);
// 在中序數組中定位根節點下標(這一步可以用Map優化)
for (int i = inLeft; i <= inRight; i++) {
if (rootVal == inorder[i]){ //如果找到根節點
pIndex = i; //記錄中序數組中根節點的下標
break;
}
}
//這裏傳入新的下標的公式,可以自己在草稿紙上算一下。
//前序和中序數組的左子樹區間
root.left = creatTree(preorder, inorder, preLeft+1, pIndex-inLeft+preLeft, inLeft, pIndex-1);
//前序和中序數組的右子樹區間
root.right = creatTree(preorder, inorder, pIndex-inLeft+preLeft+1, preRight, pIndex+1, inRight);
return root;
}
}
使用HashMap進行優化
/**
* 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) {
//判斷輸入數據是否正確,可以不寫
int preorderLen = preorder.length; //獲得兩個數組的長度
int inorderLen = inorder.length;
if (preorderLen != inorderLen){ //判斷長度是否相等
throw new RuntimeException("Incorrect input data!");
}
//使用map存儲中序數組,幫助我們快速定位根節點
Map<Integer,Integer> map = new HashMap<>(preorder.length);
for (int i = 0; i < preorder.length; i++) {
map.put(inorder[i],i); //注意這裏是把中序數組中的值當做鍵,下標當做值,便於查找
}
//創建二叉樹
return creatTree(preorder, map,0, preorder.length-1, 0, inorder.length-1);
}
/**
*
* @param preorder 前序遍歷的數組
* @param map 存放中序遍歷數組的map
* @param preLeft 要使用的前序遍歷數組的起始下標
* @param preRight 要使用的前序遍歷數組的結束下標
* @param inLeft 要使用的中序遍歷數組的起始下標
* @param inRight 要使用的中序遍歷數組的結束下標
* @return
*/
private TreeNode creatTree(int[] preorder, Map<Integer,Integer> map, int preLeft, int preRight, int inLeft, int inRight) {
//遞歸終止條件
if (preLeft > preRight || inLeft > inRight){
return null;
}
//遞歸體
// 前序數組中的第一個節點就是根節點
int rootVal = preorder[preLeft]; //獲取根節點的值
// 先把根節點建立出來
TreeNode root = new TreeNode(rootVal);
// 在中序數組中定位根節點下標
int pIndex = map.get(rootVal);
//這裏傳入新的下標的公式,可以自己在草稿紙上算一下。
//前序和中序數組的左子樹區間
root.left = creatTree(preorder, map, preLeft+1, pIndex-inLeft+preLeft, inLeft, pIndex-1);
//前序和中序數組的右子樹區間
root.right = creatTree(preorder, map, pIndex-inLeft+preLeft+1, preRight, pIndex+1, inRight);
return root;
}
}