《劍指offer》之重建二叉樹

前言

今天的刷的題目是關於樹結構的。爲了更好的解題,我們先來了解一下前序遍歷、中序遍歷和後續遍歷。
前序遍歷:就是從根節點–>左節點–>右節點
就是先從找根節點,然後找左節點。如果左節點上還有子節點,就接着找自己點的根節點,左節點,左節點這樣。如下圖,數字的順序就是前序遍歷的順序。
在這裏插入圖片描述

中序遍歷: 左節點–> 根節點–> 右節點
中序邊臨是先找樹的左節點,如果左節點還有子節點,就接着找子節點的左節點,然後根節點,然後右節點。如下圖:
在這裏插入圖片描述

後序遍歷:左節點–> 右節點–> 根節點
就是先遍歷左右節點,最後是根節點,如果左右節點還有子節點,就先遍歷子節點的左節點、然後右節點,然後根節點。如圖:
在這裏插入圖片描述
好了,知道了前序中序後序遍歷,我們來看題目。

題目

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{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}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章