1.题目描述
给你一棵二叉树的根节点 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:
输入:root = [1,2]
输出:
[["","1",""],
["2","",""]]
示例 2:
输入:root = [1,2,3,null,4]
输出:
[["","","","1","","",""],
["","2","","","","3",""],
["","","4","","","",""]]
2.解题思路与代码
2.1 解题思路
这是一道二叉树遍历的综合运用题目,通过分析题意,这道题的关键就是需要求出树的高度,求出树的高度之后便能够题目给出节点左右子节点列位置的计算公式求出左右子节点的索引。我们选择使用二叉树的层序遍历来计算树的高度,利用层序遍历特性,当放入队列的次数等于队列长度时表示一层遍历完成,此时树的高度增加一,这里需要注意的是由于题目要求根结点的高度是 0 ,那么高度从 -1 开始初始化。代码如下:
int height = -1;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int count = 1;
while (!queue.isEmpty()) {
// 一层遍历完成后高度加 1
if (queue.size() == count) {
height++;
count = 0;
}
TreeNode poll = queue.poll();
if (poll.left != null) {
queue.offer(poll.left);
count++;
}
if (poll.right != null) {
queue.offer(poll.right);
count++;
}
}
求出高度之后便开始按照题目要求将二叉树用二维数组进行表示。展示二叉树我们同样选择使用层序遍历,不同的是这里使用内部类 Info 对节点进行包装,Info 包含三个参数:节点所在行 row、节点所在列 col 和节点 node。
static class Info {
int row;
int col;
TreeNode node;
public Info(int row, int col, TreeNode node) {
this.row = row;
this.col = col;
this.node = node;
}
}
通过这三个参数我们便能够在层序遍历时取出节点,然后根据该节点的行和列计算出这个节点的左右子节点所在行和列,由于我们是计算节点的左右自己点位置,因此是计算当前节点下一层的位置,于是需要对计算公式进行修改,左节点所在列为当当前节点所在列减去二的二叉树高度减去当前节点行次方,即 node.col - (int) (Math.pow(2, height - r)) ,同理右子节点所在列为 node.col + (int) (Math.pow(2, height - r)) 。通过使用 Info 包装节点和公式的修改,二叉树的展示就变的非常简单了。代码如下:
// 根据二叉树高度计算二维数组的行数和列数
int M = height + 1;
int N = (int) (Math.pow(2, height + 1)) - 1;
List<List<String>> ans = new ArrayList<>();
Queue<Info> queue2 = new LinkedList<>();
count = 1;
// 初始化第一行,将根结点放入中点
int c = N / 2;
int r = 0;
queue2.offer(new Info(0, c, root));
String[] tmp = new String[N];
Arrays.fill(tmp,"");
tmp[c] = String.valueOf(root.val);
while (!queue2.isEmpty()) {
// 遍历完一层之后,将结果数组放入结果列表中,并初始化一个新的数组存放下一层结果
if (queue2.size() == count) {
r++;
count = 0;
ans.add(Arrays.asList(tmp));
tmp = new String[N];
Arrays.fill(tmp,"");
}
Info poll = queue2.poll();
if (poll.node.left != null) {
// 计算左节点所在列
int lc = poll.col - (int) (Math.pow(2, height - r));
queue2.offer(new Info(r, lc, poll.node.left));
tmp[lc]= String.valueOf(poll.node.left.val);
count++;
}
if (poll.node.right != null) {
// 计算右节点所在行
int rc = poll.col + (int) (Math.pow(2, height - r));
queue2.offer(new Info(r, rc, poll.node.right));
tmp[rc]= String.valueOf(poll.node.right.val);
count++;
}
}
2.2 代码
class Solution {
public List<List<String>> printTree(TreeNode root) {
int height = -1;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int count = 1;
while (!queue.isEmpty()) {
if (queue.size() == count) {
height++;
count = 0;
}
TreeNode poll = queue.poll();
if (poll.left != null) {
queue.offer(poll.left);
count++;
}
if (poll.right != null) {
queue.offer(poll.right);
count++;
}
}
int M = height + 1;
int N = (int) (Math.pow(2, height + 1)) - 1;
List<List<String>> ans = new ArrayList<>();
Queue<Info> queue2 = new LinkedList<>();
count = 1;
int c = N / 2;
int r = 0;
queue2.offer(new Info(0, c, root));
String[] tmp = new String[N];
Arrays.fill(tmp,"");
tmp[c] = String.valueOf(root.val);
while (!queue2.isEmpty()) {
if (queue2.size() == count) {
r++;
count = 0;
ans.add(Arrays.asList(tmp));
tmp = new String[N];
Arrays.fill(tmp,"");
}
Info poll = queue2.poll();
if (poll.node.left != null) {
int lc = poll.col - (int) (Math.pow(2, height - r));
queue2.offer(new Info(r, lc, poll.node.left));
tmp[lc]= String.valueOf(poll.node.left.val);
count++;
}
if (poll.node.right != null) {
int rc = poll.col + (int) (Math.pow(2, height - r));
queue2.offer(new Info(r, rc, poll.node.right));
tmp[rc]= String.valueOf(poll.node.right.val);
count++;
}
}
return ans;
}
static class Info {
int row;
int col;
TreeNode node;
public Info(int row, int col, TreeNode node) {
this.row = row;
this.col = col;
this.node = node;
}
}
}
2.3 测试结果
通过测试
3.总结
- 首先计算出二叉树的高度
- 使用 Info 包装节点所在行、列和节点,并使用层序遍历二叉树,并计算节点左右子节点的位置