題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重復的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
解題所需的知識
二叉樹的遍歷
這個先中后,是根據何時遍歷根節點命名的,左的優先級大於后,比如先序就先遍歷根結點,再遍歷左節點,最后遍歷右節點,中序同理,先左中根最后右,后序,先左再右后根。
二叉樹的先序遍歷
來! 根據上面的的順序我們來走一遍,先根再左最后右。
首先,顯而意見,1是根節點
那么現在往左走,發現 2,4,7 也是一棵二叉樹,他也是二叉樹,我們可不能區別對待,所以理應也滿足先序遍歷,先根再左最后右。那么2就是這顆小二叉樹的根節點啦。
找到了小二叉樹的根節點,按照先序再走左,發現4,7也是一棵二叉樹,這顆小小二叉樹也得滿足先序哦,4為根節點,再走左,發現左沒了,還記得先序得遍歷規則嘛 先根再左后右,左沒了那就輪到右啦,所以應該走7了,走完7以后,4,7這棵小小小二叉樹算是走完了,走完之后該走2,4,7這顆小二叉樹的右節點了,依次類推哦。
先序遍歷為 1,2,4,7,3,5,6,8
二叉樹的中序遍歷
同上 4,7,2,1,5,3,8,6
二叉樹的后序遍歷
同上 7,4,2,5,8,6,3,1
根據先序,中序構建二叉樹
舉例 前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}
首先,先序先遍歷根節點,那么1顯然就是最上面的那個根節點,中序是中間遍歷根節點,那么顯然可以得出如下圖
那么繼續去前序得數組中找,發現4,7,2最先出現的是2,那顯然2是4,7,2的根結點,去中序找,4,7都在2之前,那顯然都是2的左子樹。
再去先序找,發現4先出現,那么4就是4,7的根節點,去中序找,發現7在4的右邊,說明是右子樹。
右子樹依次類推。。。。。
代碼實現
人用迭代,神用遞歸
我們用遞歸的思想,首先先序{1,2,4,7,3,5,6,8},中序{4,7,2,1,5,3,8,6},那么我們找到1是根節點:
那么現在我們把4,7,2當成一棵二叉樹,那么先序從上面知道是{2,4,7} 中序根據上面也知道是{4,7,2},那接下來跟我們找出1是根節點然后分左右是不是一模一樣,只不過先序的數組和中序的數組變了
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
//前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
int len = pre.length;
TreeNode root = new TreeNode(pre[0]);
//說明只剩下一個了,表示葉子節點,遞歸可以退出了
if (pre.length == 1) {
root.left = null;
root.right = null;
return root;
}
//中間值 在{4,7,2,1,5,3,8,6} 這個中間值第一次應該是3
int flag = 0;
for (int i = 0; i < len; i++) {
//在中序中找到
if (pre[0] == in[i]) {
flag = i;
break;
}
}
if (flag > 0) {
//左子樹的先序
int[] leftPre = new int[flag];
//左子樹的中序
int[] leftIn = new int[flag];
for (int j = 0; j < flag; j++) {
leftPre[j] = pre[j + 1];
}
for (int j = 0; j < flag; j++) {
leftIn[j] = in[j];
}
//左子樹遞歸
root.left = reConstructBinaryTree(leftPre, leftIn);
} else {
root.left = null;
}
if (pre.length - flag - 1 > 0) {
//右子樹的先序,長度為 總-根-左子樹
int[] rightPre = new int[pre.length - 1 - flag];
//右子樹的中序
int[] rightIn = new int[pre.length - 1 - flag];
for (int j = flag + 1; j < len; j++) {
//右子樹中序,為什么要j-flag-1呢 因為我的rightIn要從0開始 而j是k+1開始的 ,所以很尷尬,只能用j-flag-1
rightIn[j - flag - 1] = in[j];
rightPre[j - flag - 1] = pre[j];
}
root.right = reConstructBinaryTree(rightPre, rightIn);
} else {
root.right = null;
}
return root;
}
}