leetcode刷题日记-【655. 输出二叉树】

99 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情

题目描述

给你一棵二叉树的根节点 root ,请你构造一个下标从 0 开始、大小为 m x n 的字符串矩阵 res ,用以表示树的 格式化布局 。构造此格式化布局矩阵需要遵循以下规则:

树的 高度 为 height ,矩阵的行数 m 应该等于 height + 1 。 矩阵的列数 n 应该等于 2height+1 - 1 。 根节点 需要放置在 顶行 的 正中间 ,对应位置为 res[0][(n-1)/2] 。 对于放置在矩阵中的每个节点,设对应位置为 res[r][c] ,将其左子节点放置在 res[r+1][c-2height-r-1] ,右子节点放置在 res[r+1][c+2height-r-1] 。 继续这一过程,直到树中的所有节点都妥善放置。 任意空单元格都应该包含空字符串 "" 。 返回构造得到的矩阵 res 。

 

 

示例 1: image.png

输入:root = [1,2] 输出: [["","1",""],  ["2","",""]] 示例 2:

image.png

输入:root = [1,2,3,null,4] 输出: [["","","","1","","",""],  ["","2","","","","3",""],  ["","","4","","","",""]]  

提示:

  • 树中节点数在范围 [1, 210] 内
  • -99 <= Node.val <= 99
  • 树的深度在范围 [1, 10] 内

解题思路

矩阵的行代表每一行节点的值,因为矩阵的列数n=2height+1 - 1,一定是个奇数。根节点存在与顶行的正中间,即res[0][(n-1)/2]。

剩下的叶子节点位置如下排布:

假设父节点位置为行位置为a,列为之为b,则它的叶子节点在矩阵中的行位置为a+b,列位置为 左叶子节点=b-2height-a-1;右叶子节点=b+2height-a-1;以此类推得到矩阵res。

因为所有位置都和height有关系,所以最开始需要求出height的值。

可以采用广度优先的方法:

先设置一个height值,初始化为0,将当前层的所有节点放入一个数组中,然后判断数组内容是否为空,为空则直接返回height;

如果不为空,则遍历这个数组,将数组中节点的做右叶子节点放入新数组中,再将其赋值到到要遍历的数组中,然后累加height。

接下来就是获取m和n。

因为整个矩阵中只有根节点比较特殊,根节点元素位于第一行中间的位置,其它节点都是按照父节点的左右按照公式分布的,所以这里可以用一个递归来设置矩阵数据,递归的终止条件为二叉树所有节点为空;

递归中如果还有不为空的节点,则继续调用递归链路设置res矩阵。

代码实现

public List<List<String>> printTree(TreeNode root) {
    List<List<String>> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    // 求出height
    int height = getHeight(root);
    int m = height + 1;
    int n = (int) Math.pow(2,height+1) - 1;
    int[][] arr = new int[m][n];
    for (int i = 0;i < m;i ++) {
        for (int j = 0;j < n;j ++) {
            arr[i][j] = -100;
        }
    }
    // 确定首行的位置
    int a = 0;
    int b = (n-1)/2;
    arr[a][b] = root.val;
    // 根据上一行的位置,获取下一行的位置
    setLeafNode(arr,a,b,height,root);
    getListByArr(res,arr);
    return res;
}

private void getListByArr(List<List<String>> res, int[][] arr) {
    for (int[] ints : arr) {
        List<String> strings = new ArrayList<>();
        for (int anInt : ints) {
            if (anInt == -100) {
                strings.add("");
            } else  {
                strings.add(String.valueOf(anInt));
            }
        }
        res.add(strings);
    }
}

/**
 * 根据父节点位置设置叶子节点位置
 * @param arr 需要设置的二维数组
 * @param a 父节点行位置
 * @param b 父节点列位置
 * @param height 总层高
 * @param nodes 二叉树
 */
private void setLeafNode(int[][] arr, int a, int b, int height,TreeNode nodes) {
    // 如果节点中的元素为空则直接返回
    if (nodes == null) {
        return;
    }
    // 行位置
    int x = a + 1;
    List<TreeNode> newNodes = new ArrayList<>();
    // 右叶子节点
    if (nodes.right != null) {
        newNodes.add(nodes.right);
        int y = b + (int) Math.pow(2,height-a-1);
        // b+2height-a-1
        arr[x][y] = nodes.right.val;
        setLeafNode(arr,x,y,height,nodes.right);
    }
    // 左叶子节点
    if (nodes.left != null) {
        newNodes.add(nodes.left);
        int y = b - (int) Math.pow(2,height-a-1);
        // b+2height-a-1
        arr[x][b - (int) Math.pow(2,height-a-1)] = nodes.left.val;
        setLeafNode(arr,x,y,height,nodes.left);
    }
}

/**
 * 获取height
 */
private int getHeight(TreeNode root) {
    if (root == null) {
        return 0;
    }
    List<TreeNode> nodes = new ArrayList<>();
    nodes.add(root);
    int height = 0;
    while (!nodes.isEmpty()) {
        List<TreeNode> newNodes = new ArrayList<>();
        for (TreeNode node : nodes) {
            if (node.right != null) {
                newNodes.add(node.right);
            }
            if (node.left != null) {
                newNodes.add(node.left);
            }
        }
        if (!newNodes.isEmpty()) {
            height++;
        }
        nodes = newNodes;
    }
    return height;
}