The Print Binary Tree problem requires you to represent a binary tree in a 2D string array (matrix) according to specific formatting rules. The goal is to visually "print" the tree such that:
""
.The input is the root node of a binary tree. The output is a 2D list (matrix) of strings that visually represents the tree as described.
Constraints:
The challenge here is to determine where each node's value should be placed in the 2D array so that the tree appears centered and visually correct. At first, you might consider a brute-force approach: traverse the tree and try to insert values row by row, but quickly realize that without knowing the total width and the correct positions, the output will not be properly formatted.
To optimize, we need to:
This leads to a recursive, divide-and-conquer approach where for each node, we calculate its position based on its subtree's range.
Let's break down the solution step by step:
2^height - 1
(always an odd number), ensuring enough space for all nodes and their positions.""
with dimensions height x width
.(left + right) // 2
and place the node's value there.We use recursion because it naturally fits the tree structure, and splitting the column range ensures each subtree is centered below its parent.
Sample Input:
1 / \ 2 3 \ 4
Step 1: Find Height
The tree has 3 levels (height = 3).
Step 2: Calculate Width
Width = 23 - 1 = 7.
Step 3: Initialize Matrix
Create a 3x7 matrix filled with empty strings.
Step 4: Place Values
1
at row 0, column 3 (center).2
: row 1, columns 0-2, place at column 1.3
: row 1, columns 4-6, place at column 5.2
's right child 4
: row 2, columns 2-2, place at column 2.Final Output:
[ ["", "", "", "1", "", "", ""], ["", "2", "", "", "", "3", ""], ["", "", "4", "", "", "", ""] ]
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def printTree(self, root):
def getHeight(node):
if not node:
return 0
return 1 + max(getHeight(node.left), getHeight(node.right))
def fill(res, node, row, left, right):
if not node:
return
mid = (left + right) // 2
res[row][mid] = str(node.val)
fill(res, node.left, row + 1, left, mid - 1)
fill(res, node.right, row + 1, mid + 1, right)
height = getHeight(root)
width = (1 << height) - 1
res = [["" for _ in range(width)] for _ in range(height)]
fill(res, root, 0, 0, width - 1)
return res
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
int getHeight(TreeNode* node) {
if (!node) return 0;
return 1 + std::max(getHeight(node->left), getHeight(node->right));
}
void fill(vector<vector<string>>& res, TreeNode* node, int row, int left, int right) {
if (!node) return;
int mid = (left + right) / 2;
res[row][mid] = to_string(node->val);
fill(res, node->left, row + 1, left, mid - 1);
fill(res, node->right, row + 1, mid + 1, right);
}
vector<vector<string>> printTree(TreeNode* root) {
int height = getHeight(root);
int width = (1 << height) - 1;
vector<vector<string>> res(height, vector<string>(width, ""));
fill(res, root, 0, 0, width - 1);
return res;
}
};
// Definition for a binary tree node.
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
public List<List<String>> printTree(TreeNode root) {
int height = getHeight(root);
int width = (int)Math.pow(2, height) - 1;
List<List<String>> res = new ArrayList<>();
for (int i = 0; i < height; i++) {
List<String> row = new ArrayList<>();
for (int j = 0; j < width; j++) row.add("");
res.add(row);
}
fill(res, root, 0, 0, width - 1);
return res;
}
private int getHeight(TreeNode node) {
if (node == null) return 0;
return 1 + Math.max(getHeight(node.left), getHeight(node.right));
}
private void fill(List<List<String>> res, TreeNode node, int row, int left, int right) {
if (node == null) return;
int mid = (left + right) / 2;
res.get(row).set(mid, Integer.toString(node.val));
fill(res, node.left, row + 1, left, mid - 1);
fill(res, node.right, row + 1, mid + 1, right);
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {string[][]}
*/
var printTree = function(root) {
function getHeight(node) {
if (!node) return 0;
return 1 + Math.max(getHeight(node.left), getHeight(node.right));
}
function fill(res, node, row, left, right) {
if (!node) return;
let mid = Math.floor((left + right) / 2);
res[row][mid] = node.val.toString();
fill(res, node.left, row + 1, left, mid - 1);
fill(res, node.right, row + 1, mid + 1, right);
}
let height = getHeight(root);
let width = (1 << height) - 1;
let res = [];
for (let i = 0; i < height; i++) {
res.push(new Array(width).fill(""));
}
fill(res, root, 0, 0, width - 1);
return res;
};
Brute-force approach: If you tried to simulate the output by visiting every possible position in the matrix for each node, the time complexity could be as bad as O(N*W), where N is the number of nodes and W is the width of the matrix.
Optimized approach (as above):
The recursion stack will also use O(H) space due to the depth of recursion.
The Print Binary Tree problem is a great exercise in combining tree traversal with careful index calculation. The key insight is to use the tree's height to determine the correct matrix size, and then recursively place each node's value at the center of its allotted range. This ensures symmetry and correctness. By leveraging recursion and simple arithmetic, the solution remains both elegant and efficient, with clear logic that closely mirrors the tree's own structure.