概述
本題來自牛客網-劍指offer在線測評
題目描述
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
原理與實現
思想:二分、遞歸
關鍵是:利用前序序列根節點在前找到根節點,用根節點去中序序列劃分成兩部分,左部分是左子樹,右部分是右子樹。再利用子樹長度去前序序列把前序序列中的左右子樹找出來,同時可以找出根節點。遞歸進行此步驟,如果子樹長度爲0,則不需要生成子問題。
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
/**
* 關鍵是:利用前序序列根節點在前找到根節點,用根節點去中序序列劃分成兩部分,左部分是左子樹,右部分是右子樹。再利用子樹長度去前序序列把前序序列中的左右子樹找出來,同時可以找出根節點。遞歸進行此步驟,如果子樹長度爲0,則不需要生成子問題。
*/
public class Solution {
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
TreeNode root = new TreeNode(pre[0]);
build(root, pre, 0, pre.length, in, 0, in.length);
return root;
}
/**
* 遞歸和二分思想,將問題不斷劃分,直到問題容易解決。
* 做法是:對於一個根節點,先去中序序列中找到根節點的值所在位置,利用這個位置分成2部分,左部分的中序序列長度即爲前序序列中左部分的中序序列長度,右部分亦然。
* 然後開始生成子問題,如果序列長度爲0則不需要生成子問題。否則:利用前序序列第一個元素爲根節點的性質生成根節點,然後構造子問題。
* @param root 根節點
* @param pre 前序序列 範圍是[pleft,pright)
* @param in 中序序列 範圍是[ileft,iright)
*/
public void build(TreeNode root, int[] pre, int pleft, int pright, int[] in, int ileft, int iright) {
int i;
for (i = ileft; i < iright; i++) {
if (in[i] == root.val) {//從中序序列尋找根節點的位置
break;
}
}
int t = i - ileft;//左子樹長度
if (t > 0) {//左子樹長度爲0時不必生成子問題
root.left = new TreeNode(pre[pleft + 1]);
build(root.left, pre, pleft + 1, pleft + 1 + t, in, ileft, i);
}
if (pright - pleft - 1 - t > 0) {//右子樹長度爲0時不必生成子問題
root.right = new TreeNode(pre[pleft + 1 + t]);
build(root.right, pre, pleft + 1 + t, pright, in, i + 1, iright);
}
}
}