巧用遞迴構造二叉樹
阿新 • • 發佈:2021-02-02
leetcode第105題:從前序與中序遍歷序列構造二叉樹
難度:中等;通過率:68%
注意:你可以假設樹中沒有重複的元素。
例如,給出:
前序遍歷 preorder = [3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:
解題思路
絕大多數二叉樹的題目,都能夠使用遞迴的思想來解決,所以面對二叉樹類的題目,首先應該想到遞迴,這樣不僅可以省去大量的if-else操作,也能使得程式碼簡潔明瞭。對於這個題,我們應該明確的一個主要思路是:
前序遍歷的順序是——中左右,即根結點的位置在左右子結點前面;
則遞迴操作為:通過前序陣列構建根結點,再通過中序陣列找到並遞迴構造左右子樹。
具體解答為:
1.定義一個HashMap,建立前序元素與中序元素的對映關係,用於快速找到中序陣列中根結點的位置;
2.對於整棵樹,首先通過前序陣列找到根結點位置,再通過HashMap找到中序陣列中根結點的位置;
3.構造根結點;
4.計算左子樹的長度=中序根結點位置-中序最左結點位置;(注意這裡的最左結點不是整棵樹的最左結點,而是每次傳入的不同樹的最左結點)。
5.將整棵樹拆分成:
左子樹——前序陣列[前序最左結點+1,前序最左結點+左子樹長度],中序陣列[中序最左結點,中序根結點-1];
6.分別將左右子樹作為新的整棵樹,重複2,3,4,5的過程遞迴構造左子樹和右子樹;
7.返回根結點。
程式碼
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
//建立中序元素與前序元素的對映關係,用於快速找到中序陣列中的根結點。
HashMap<Integer,Integer>index;
public TreeNode buildTree(int[] preorder, int[] inorder) {
//新增對映,一次構造,多次使用。
index=new HashMap<>();
for(int i=0;i<inorder.length;i++){
index.put(inorder[i],i);
}
return myBuild(preorder,inorder,0,preorder.length-1,0,inorder.length-1);
}
//遞迴構造樹
public TreeNode myBuild(int[]preorder,int[]inorder,int pre_left,int pre_right,int in_left,int in_right){
//無子樹,返回null
if(in_left>in_right)return null;
int pre_root=pre_left;
//獲取中序根結點位置
int in_root=index.get(preorder[pre_root]);
//構造根結點
TreeNode root=new TreeNode(preorder[pre_root]);
//計算左子樹長度
int left_size=in_root-in_left;
//遞迴構造左子樹
root.left=myBuild(preorder,inorder,pre_left+1,pre_left+left_size,in_left,in_root-1);
//遞迴構造右子樹
root.right=myBuild(preorder,inorder,pre_left+left_size+1,pre_right,in_root+1,in_right);
return root;
}
}