前言
今天的刷的題目是關於樹結構的。爲了更好的解題,我們先來了解一下前序遍歷、中序遍歷和後續遍歷。
前序遍歷:就是從根節點–>左節點–>右節點
就是先從找根節點,然後找左節點。如果左節點上還有子節點,就接着找自己點的根節點,左節點,左節點這樣。如下圖,數字的順序就是前序遍歷的順序。
中序遍歷: 左節點–> 根節點–> 右節點
中序邊臨是先找樹的左節點,如果左節點還有子節點,就接着找子節點的左節點,然後根節點,然後右節點。如下圖:
後序遍歷:左節點–> 右節點–> 根節點
就是先遍歷左右節點,最後是根節點,如果左右節點還有子節點,就先遍歷子節點的左節點、然後右節點,然後根節點。如圖:
好了,知道了前序中序後序遍歷,我們來看題目。
題目
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
分析
我們首先需要創建一個二叉樹的類。
如下:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){
val=x;
}
}
這樣就可以表示一個二叉樹了啦。
然後知道前序和中序。那麼前序的第一個元素就是根節點,然後在中序的數組中找到根節點的位置,那麼根節點左邊的,都是左節點,右邊的都是右節點。
比如 前序 pre{1,2,4,7,3,5,6,8} 中序 in {4,7,2,1,5,3,8,6}
那麼第一次,從in 中找1 的位置。
那麼1 的左節點樹的
前序{2,4,7}
中序爲{4,7,2}
那麼1 的右節點樹的
前序{3,5,6,8}
中序爲{,5,3,8,6}
這是一次操作,然後分別對根節點的左節點和右節點,進行相同的操作。
前序{2,4,7}
中序爲{4,7,2}
那麼根節點爲2,根節點的
左節點樹的
前序{4,7}
中序{4,7}
右節點樹爲null;
…
解法
所以採用遞歸的方法,找出根節點,然後分別將左節點和右節點遞歸存儲到二叉樹中。
public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
int length=pre.length;
if(length==0){
return null;
}
int rootVal=pre[0];
//將當前節點存入樹中
TreeNode rootNode=new TreeNode(rootVal);
for(int i=0;i<length;i++){
if(rootVal== in[i]){
rootNode.left=reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
rootNode.right=reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,length),Arrays.copyOfRange(in,i+1,length));
}
}
return rootNode;
}
這裏使用了Arrays.copyOfRange(pre,begin,end) 方法,表示中pre 數組中copy數組,從begin 索引開始,到end 結束。左閉右開。
源代碼
public class Solution {
public static void main(String[] args) {
int [] pre={1,2,4,7,3,5,6,8};
int [] in={4,7,2,1,5,3,8,6};
TreeNode treeNode=reConstructBinaryTree(pre,in);
TreeOperation.show(treeNode);
}
public static void print(TreeNode treeNode){
System.out.print(treeNode.val);
if(treeNode.left !=null ){
print(treeNode.left);
}
if(treeNode.right !=null){
print(treeNode.right);
}
System.out.println();
}
public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
int length=pre.length;
if(length==0){
return null;
}
int rootVal=pre[0];
//將當前節點存入樹中
TreeNode rootNode=new TreeNode(rootVal);
for(int i=0;i<length;i++){
if(rootVal== in[i]){
rootNode.left=reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
rootNode.right=reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,length),Arrays.copyOfRange(in,i+1,length));
}
}
return rootNode;
}
}
然後打印二叉樹,我在網上找的代碼,直接拿過來用的
參考:
按照樹形結構直觀地打印出一棵二叉樹(Java)
public class TreeOperation {
/*
樹的結構示例:
1
/ \
2 3
/ \ / \
4 5 6 7
*/
// 用於獲得樹的層數
public static int getTreeDepth(TreeNode root) {
return root == null ? 0 : (1 + Math.max(getTreeDepth(root.left), getTreeDepth(root.right)));
}
private static void writeArray(TreeNode currNode, int rowIndex, int columnIndex, String[][] res, int treeDepth) {
// 保證輸入的樹不爲空
if (currNode == null) return;
// 先將當前節點保存到二維數組中
res[rowIndex][columnIndex] = String.valueOf(currNode.val);
// 計算當前位於樹的第幾層
int currLevel = ((rowIndex + 1) / 2);
// 若到了最後一層,則返回
if (currLevel == treeDepth) return;
// 計算當前行到下一行,每個元素之間的間隔(下一行的列索引與當前元素的列索引之間的間隔)
int gap = treeDepth - currLevel - 1;
// 對左兒子進行判斷,若有左兒子,則記錄相應的"/"與左兒子的值
if (currNode.left != null) {
res[rowIndex + 1][columnIndex - gap] = "/";
writeArray(currNode.left, rowIndex + 2, columnIndex - gap * 2, res, treeDepth);
}
// 對右兒子進行判斷,若有右兒子,則記錄相應的"\"與右兒子的值
if (currNode.right != null) {
res[rowIndex + 1][columnIndex + gap] = "\\";
writeArray(currNode.right, rowIndex + 2, columnIndex + gap * 2, res, treeDepth);
}
}
public static void show(TreeNode root) {
if (root == null) System.out.println("EMPTY!");
// 得到樹的深度
int treeDepth = getTreeDepth(root);
// 最後一行的寬度爲2的(n - 1)次方乘3,再加1
// 作爲整個二維數組的寬度
int arrayHeight = treeDepth * 2 - 1;
int arrayWidth = (2 << (treeDepth - 2)) * 3 + 1;
// 用一個字符串數組來存儲每個位置應顯示的元素
String[][] res = new String[arrayHeight][arrayWidth];
// 對數組進行初始化,默認爲一個空格
for (int i = 0; i < arrayHeight; i ++) {
for (int j = 0; j < arrayWidth; j ++) {
res[i][j] = " ";
}
}
// 從根節點開始,遞歸處理整個樹
// res[0][(arrayWidth + 1)/ 2] = (char)(root.val + '0');
writeArray(root, 0, arrayWidth/ 2, res, treeDepth);
// 此時,已經將所有需要顯示的元素儲存到了二維數組中,將其拼接並打印即可
for (String[] line: res) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < line.length; i ++) {
sb.append(line[i]);
if (line[i].length() > 1 && i <= line.length - 1) {
i += line[i].length() > 4 ? 2: line[i].length() - 1;
}
}
System.out.println(sb.toString());
}
}
}
測試
反思
這裏是知道前序和中序。從中序中找到左右節點。
如果給出 中序和後序呢?
中序:{4,7,2,1,5,3,8,6}
後序:{7,4,2,3,5,8,6,1}
那如果給出 前序和後序呢?
前序:{1,2,4,7,3,5,6,8}
後序:{7,4,2,3,5,8,6,1}