加载中...
655-输出二叉树(Print Binary Tree)
发表于:2021-12-03 | 分类: 中等
字数统计: 2k | 阅读时长: 9分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/print-binary-tree

英文原文

Given the root of a binary tree, construct a 0-indexed m x n string matrix res that represents a formatted layout of the tree. The formatted layout matrix should be constructed using the following rules:

  • The height of the tree is height and the number of rows m should be equal to height + 1.
  • The number of columns n should be equal to 2height+1 - 1.
  • Place the root node in the middle of the top row (more formally, at location res[0][(n-1)/2]).
  • For each node that has been placed in the matrix at position res[r][c], place its left child at res[r+1][c-2height-r-1] and its right child at res[r+1][c+2height-r-1].
  • Continue this process until all the nodes in the tree have been placed.
  • Any empty cells should contain the empty string "".

Return the constructed matrix res.

 

Example 1:

Input: root = [1,2]
Output: 
[["","1",""],
 ["2","",""]]

Example 2:

Input: root = [1,2,3,null,4]
Output: 
[["","","","1","","",""],
 ["","2","","","","3",""],
 ["","","4","","","",""]]

 

Constraints:

  • The number of nodes in the tree is in the range [1, 210].
  • -99 <= Node.val <= 99
  • The depth of the tree will be in the range [1, 10].

中文题目

在一个 m*n 的二维字符串数组中输出二叉树,并遵守以下规则:

  1. 行数 m 应当等于给定二叉树的高度。
  2. 列数 n 应当总是奇数。
  3. 根节点的值(以字符串格式给出)应当放在可放置的第一行正中间。根节点所在的行与列会将剩余空间划分为两部分(左下部分和右下部分)。你应该将左子树输出在左下部分,右子树输出在右下部分。左下和右下部分应当有相同的大小。即使一个子树为空而另一个非空,你不需要为空的子树输出任何东西,但仍需要为另一个子树留出足够的空间。然而,如果两个子树都为空则不需要为它们留出任何空间。
  4. 每个未使用的空间应包含一个空的字符串""
  5. 使用相同的规则输出子树。

示例 1:

输入:
     1
    /
   2
输出:
[["", "1", ""],
 ["2", "", ""]]

示例 2:

输入:
     1
    / \
   2   3
    \
     4
输出:
[["", "", "", "1", "", "", ""],
 ["", "2", "", "", "", "3", ""],
 ["", "", "4", "", "", "", ""]]

示例 3:

输入:
      1
     / \
    2   5
   / 
  3 
 / 
4 
输出:
[["",  "",  "", "",  "", "", "", "1", "",  "",  "",  "",  "", "", ""]
 ["",  "",  "", "2", "", "", "", "",  "",  "",  "",  "5", "", "", ""]
 ["",  "3", "", "",  "", "", "", "",  "",  "",  "",  "",  "", "", ""]
 ["4", "",  "", "",  "", "", "", "",  "",  "",  "",  "",  "", "", ""]]

注意: 二叉树的高度在范围 [1, 10] 中。

通过代码

官方题解

方法一:递归【通过】

创建一个长度为 $height\times(2^{height}-1)$ 的数组 $res$,其中 $height$ 是树的高度。先使用空字符串 "" 填充数组 $res$。然后递归调用 fill(res, root, i, l, r) 将节点的值输出到数组 $res$ 中,其中 $i$ 表示当前节点所在层数,$l$ 和 $r$ 表示当前子树在数组 $res$ 中的左右边界,当前节点被输出到数组 $res$ 第 $i$ 行的第 $l$ 列和第 $r$ 列中间位置上。

在递归方法中,执行以下步骤:

  1. 如果到达树的末尾,即 root = null,直接返回。

  2. 确定当前节点所在的列 $j=(l+r)/2$。将当前节点输出到数组 $res$ 的第 $i$ 行第 $j$ 列,即 $res[i][j]$。

  3. 递归调用 fill(res, root.left, i + 1, l, (l + r) / 2),输出 $root$ 的左子树。

  4. 递归调用 fill(res, root.right, i + 1, (l + r + 1) / 2, r),输出 $root$ 的右子树。

注意:在第三步和第四步的递归调用中需要更新行号,确保子节点可以输出的正确的位置。另外,也要根据 $l$ 和 $r$ 更新子树的左右边界。

另外,创建方法 getHeight(root), 用于计算 $root$ 为根节点的树高度 $height$。递归遍历树的所有分支,从中找出最深的一个分支作为树的高度。

最后,将数组 $res$ 转换成题目要求格式。

[solution1-Java]
public class Solution { public List<List<String>> printTree(TreeNode root) { int height = getHeight(root); String[][] res = new String[height][(1 << height) - 1]; for(String[] arr:res) Arrays.fill(arr,""); List<List<String>> ans = new ArrayList<>(); fill(res, root, 0, 0, res[0].length); for(String[] arr:res) ans.add(Arrays.asList(arr)); return ans; } public void fill(String[][] res, TreeNode root, int i, int l, int r) { if (root == null) return; res[i][(l + r) / 2] = "" + root.val; fill(res, root.left, i + 1, l, (l + r) / 2); fill(res, root.right, i + 1, (l + r + 1) / 2, r); } public int getHeight(TreeNode root) { if (root == null) return 0; return 1 + Math.max(getHeight(root.left), getHeight(root.right)); } }

复杂度分析

  • 时间复杂度:$O(h*2^h)$,其中 $h$ 是树的高度,填充长度为 $h\times(2^h-1)$ 的数组 $res$。

  • 空间复杂度:$O(h*2^h)$,数组 $res$ 的长度为 $h\times(2^h-1)$。

方法二:使用队列(BFS) 【通过】

算法

也可以使用广度优先搜索解决该问题。使用类 $Params$ 存储树的节点 $node$,类中包含该节点的值,所在层数 $i$,和以该节点为根的子树的左边界 $l$ 和右边界 $r$。

初始化一个与 方法一 用途相同的数组 $res$,将根节点 $root$ 加入到队列 $queue$ 中,然后执行以下步骤。

  1. 从队列中移除元素 $p$。

  2. 将该元素的值输出到 $res[p.i][(p.l + p.r) / 2]$,其中 $i$ 表示当前节点的所在行,$l$ 和 $r$ 表示当前子树的左右边界。这些值都是在节点加入 $queue$ 之前就已经计算好的。

  3. 如果节点 $p$ 有左孩子,则将它的左孩子加入到 $queue$,同时计算左孩子的所在行,和以该节点为根的子树的左右边界。

  4. 如果节点 $p$ 有右孩子,则将它的右孩子加入到 $queue$,同时计算右孩子的所在行,和以该节点为根的子树的左右边界。

  5. 回复步骤一到四,直到 $queue$ 为空。

最后,将数组 $res$ 转换为题目要求的格式返回。

[solution2-Java]
public class Solution /** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { class Params { Params(TreeNode n, int ii, int ll, int rr) { root = n; i = ii; l = ll; r = rr; } TreeNode root; int i, l, r; } public List < List < String >> printTree(TreeNode root) { int height = getHeight(root); System.out.println(height); String[][] res = new String[height][(1 << height) - 1]; for (String[] arr: res) Arrays.fill(arr, ""); List < List < String >> ans = new ArrayList < > (); fill(res, root, 0, 0, res[0].length); for (String[] arr: res) ans.add(Arrays.asList(arr)); return ans; } public void fill(String[][] res, TreeNode root, int i, int l, int r) { Queue < Params > queue = new LinkedList(); queue.add(new Params(root, 0, 0, res[0].length)); while (!queue.isEmpty()) { Params p = queue.remove(); res[p.i][(p.l + p.r) / 2] = "" + p.root.val; if (p.root.left != null) queue.add(new Params(p.root.left, p.i + 1, p.l, (p.l + p.r) / 2)); if (p.root.right != null) queue.add(new Params(p.root.right, p.i + 1, (p.l + p.r + 1) / 2, p.r)); } } public int getHeight(TreeNode root) { Queue < TreeNode > queue = new LinkedList(); queue.add(root); int height = 0; while (!queue.isEmpty()) { height++; Queue < TreeNode > temp = new LinkedList(); while (!queue.isEmpty()) { TreeNode node = queue.remove(); if (node.left != null) temp.add(node.left); if (node.right != null) temp.add(node.right); } queue = temp; } return height; } }

复杂度分析

  • 时间复杂度:$O(h*2^h)$,其中 $h$ 是树的高度,填充长度为 $h\times(2^h-1)$ 的数组 $res$。

  • 空间复杂度:$O(h*2^h)$,数组 $res$ 的长度为 $h\times(2^h-1)$。

统计信息

通过次数 提交次数 AC比率
9927 16535 60.0%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
654-最大二叉树(Maximum Binary Tree)
下一篇:
658-找到 K 个最接近的元素(Find K Closest Elements)
本文目录
本文目录