Given a n * n
matrix grid
of 0's
and 1's
only. We want to represent grid
with a Quad-Tree.
Return the root of the Quad-Tree representing grid
.
A Quad-Tree is a tree data structure in which each internal node has exactly four children. Besides, each node has two attributes:
val
: True if the node represents a grid of 1's or False if the node represents a grid of 0's. Notice that you can assign the val
to True or False when isLeaf
is False, and both are accepted in the answer.isLeaf
: True if the node is a leaf node on the tree or False if the node has four children.class Node { public boolean val; public boolean isLeaf; public Node topLeft; public Node topRight; public Node bottomLeft; public Node bottomRight; }
We can construct a Quad-Tree from a two-dimensional area using the following steps:
1's
or all 0's
) set isLeaf
True and set val
to the value of the grid and set the four children to Null and stop.isLeaf
to False and set val
to any value and divide the current grid into four sub-grids as shown in the photo.If you want to know more about the Quad-Tree, you can refer to the wiki.
Quad-Tree format:
You don't need to read this section for solving the problem. This is only if you want to understand the output format here. The output represents the serialized format of a Quad-Tree using level order traversal, where null
signifies a path terminator where no node exists below.
It is very similar to the serialization of the binary tree. The only difference is that the node is represented as a list [isLeaf, val]
.
If the value of isLeaf
or val
is True we represent it as 1 in the list [isLeaf, val]
and if the value of isLeaf
or val
is False we represent it as 0.
Example 1:
Input: grid = [[0,1],[1,0]] Output: [[0,1],[1,0],[1,1],[1,1],[1,0]] Explanation: The explanation of this example is shown below: Notice that 0 represents False and 1 represents True in the photo representing the Quad-Tree.![]()
Example 2:
Input: grid = [[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0],[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0]] Output: [[0,1],[1,1],[0,1],[1,1],[1,0],null,null,null,null,[1,0],[1,0],[1,1],[1,1]] Explanation: All values in the grid are not the same. We divide the grid into four sub-grids. The topLeft, bottomLeft and bottomRight each has the same value. The topRight have different values so we divide it into 4 sub-grids where each has the same value. Explanation is shown in the photo below:![]()
Constraints:
n == grid.length == grid[i].length
n == 2x
where 0 <= x <= 6
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
To build the Quad Tree with a brute force method, we'll examine every possible square section within the input grid. We determine if each section is uniform by checking if all its values are the same, and create a node based on that determination.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, is_leaf, value, top_left=None, top_right=None,
bottom_left=None, bottom_right=None):
self.isLeaf = is_leaf
self.val = value
self.topLeft = top_left
self.topRight = top_right
self.bottomLeft = bottom_left
self.bottomRight = bottom_right
def construct_quad_tree(grid):
def build_tree(grid, top_row, top_col, side_length):
# Check if the current grid section is uniform
if is_uniform(grid, top_row, top_col, side_length):
return Node(True, grid[top_row][top_col])
# If not uniform, divide into four quadrants and construct recursively
half_side = side_length // 2
# Recursively construct the top-left quadrant
top_left_node = build_tree(grid, top_row, top_col, half_side)
# Recursively construct the top-right quadrant
top_right_node = build_tree(grid, top_row, top_col + half_side, half_side)
# Recursively construct the bottom-left quadrant
bottom_left_node = build_tree(grid, top_row + half_side, top_col, half_side)
# Recursively construct the bottom-right quadrant
bottom_right_node = build_tree(grid, top_row + half_side, top_col + half_side, half_side)
# Create a non-leaf node with the four quadrants as children
return Node(False, True, top_left_node, top_right_node, bottom_left_node, bottom_right_node)
def is_uniform(grid, top_row, top_col, side_length):
first_value = grid[top_row][top_col]
for row_index in range(top_row, top_row + side_length):
for col_index in range(top_col, top_col + side_length):
if grid[row_index][col_index] != first_value:
return False
return True
grid_size = len(grid)
return build_tree(grid, 0, 0, grid_size)
The key is to use recursion and check if each quadrant of the grid has the same value. If it does, we can create a leaf node; otherwise, we recursively build the tree for each quadrant and combine them into a parent node.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, value, is_leaf, top_left, top_right, bottom_left, bottom_right):
self.value = value
self.is_leaf = is_leaf
self.top_left = top_left
self.top_right = top_right
self.bottom_left = bottom_left
self.bottom_right = bottom_right
def construct_quad_tree(grid):
def build_tree(grid, top, left, side_length):
# Check if the current section of the grid has the same value.
if all(grid[top + i][left + j] == grid[top][left]
for i in range(side_length) for j in range(side_length)):
return Node(grid[top][left], True, None, None, None, None)
# If values are different, divide into four quadrants.
half_side = side_length // 2
# Recursively build the tree for each quadrant.
top_left_node = build_tree(grid, top, left, half_side)
top_right_node = build_tree(grid, top, left + half_side, half_side)
bottom_left_node = build_tree(grid, top + half_side, left, half_side)
bottom_right_node = build_tree(grid, top + half_side, left + half_side, half_side)
# Create a parent node linking to the four child nodes.
# The value is arbitrary since it's not a leaf.
return Node(0, False, top_left_node, top_right_node, bottom_left_node, bottom_right_node)
grid_size = len(grid)
return build_tree(grid, 0, 0, grid_size)
Case | How to Handle |
---|---|
Null or empty input grid | Return null as the root of the quadtree is undefined for an empty grid. |
Grid of size 1x1 | Create a leaf node with the value of the single element in the grid, setting `isLeaf` to true. |
Grid with non-square dimensions (m x n where m != n) | The problem statement specifies n*n grid; the solution should throw an exception or handle this error case appropriately if encountered. |
Grid with all elements having the same value (either all 0s or all 1s) | Create a single leaf node with `isLeaf` set to true and the common value as its `val`. |
Grid with alternating 0s and 1s (maximum variation) | The solution should recursively divide the grid until it reaches the base case of a 1x1 grid or a uniform subgrid. |
Very large grid (e.g., 2^10 x 2^10) that could lead to stack overflow due to deep recursion | Consider iterative solution or techniques to limit recursion depth to prevent stack overflow, perhaps by using helper function to track recursion depth and switch to iteration past some limit. |
Invalid input values (values other than 0 or 1) | Throw an IllegalArgumentException if input values other than 0 or 1 are encountered. |
Memory constraints with extremely large grids | If memory is a huge concern, external memory algorithms or approximate solutions with limited quadtree depth might be necessary (but are likely outside the scope of a standard interview). |