Construct Quad Tree

Updated on 13 May, 2025
Construct Quad Tree header image

Problem Statement

In this problem, you are provided with a square matrix grid, composed solely of 0's and 1's. Your task is to create a Quad-Tree representation of this matrix. The Quad-Tree is a specialized tree data structure where each internal node has exactly four children. It efficiently represents data that is hierarchically divisible into quarters, which perfectly suits the needs of matrix representation where data can be markedly uniform or varied in different sectors.

The challenge lies in constructing this Quad-Tree by dividing the matrix into four quadrants until all cells in a quadrant hold the same value (either all 0's or all 1's). Each node in the Quad-Tree corresponds to a specific sub-grid and is defined with a boolean value and a boolean flag indicating whether it is a leaf node:

  • val: captures the predominant boolean value of the sub-grid. For leaf nodes, it represents the value of the area (all 0's or 1's). For non-leaf nodes, it might be arbitrarily set, as the specific mix of children's values describe the grid accurately.
  • isLeaf: signifies if the node is a leaf (i.e., the corresponding sub-grid is uniform).

The entire tree needs to be constructed following these principles iteratively or recursively until every part of the grid is represented succinctly in the Quad-Tree structure.

Examples

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

Approach and Intuition

Given the constraints and examples, the approach to solve this problem breaks down into several clear steps:

  1. Start by examining the entire grid to determine if it's a leaf node:
    • If the grid contains the same value (1's or 0's), create a leaf node indicating this uniformity.
    • If the grid contains both values, proceed to divide the grid into four quadrants or sub-grids.
  2. Recursively apply the Quad-Tree construction to each of the four sub-grids:
    • Top-left
    • Top-right
    • Bottom-left
    • Bottom-right
  3. During each recursive step, determine the nature of the sub-grid (uniform or mixed):
    • If uniform, mark the recursive call’s return as a leaf node.
    • If mixed, further sub-divide the grid.
  4. Each call should return a node which gets assigned to the parent node’s respective children (top-left, top-right, bottom-left, bottom-right).
  5. Base case for the recursion would be when the size of the grid becomes 1x1, directly returning a node with the single element as its value and isLeaf set to True.

This method ensures a methodical breakdown of the grid, leveraging the inherent divide-and-conquer paradigm which is suited for hierarchical representations like the Quad-Tree.

Solutions

  • C++
  • Java
cpp
class Solution {
public:
    Node* constructSubtree(vector<vector<int>>& matrix, int x, int y, int len) {
        if (len == 1) {
            return new Node(matrix[x][y], true);
        }

        Node* topLeftNode = constructSubtree(matrix, x, y, len / 2);
        Node* topRightNode = constructSubtree(matrix, x, y + len / 2, len / 2);
        Node* bottomLeftNode = constructSubtree(matrix, x + len / 2, y, len / 2);
        Node* bottomRightNode = constructSubtree(matrix, x + len / 2, y + len / 2, len / 2);

        if (topLeftNode -> isLeaf && topRightNode -> isLeaf && 
            bottomLeftNode -> isLeaf && bottomRightNode -> isLeaf &&
            topLeftNode -> val == topRightNode -> val && 
            topRightNode -> val == bottomLeftNode -> val && 
            bottomLeftNode -> val == bottomRightNode -> val) {
            return new Node(topLeftNode -> val, true);
        }

        return new Node(false, false, topLeftNode, topRightNode, bottomLeftNode, bottomRightNode);
    }

    Node* build(vector<vector<int>>& matrix) {
        return constructSubtree(matrix, 0, 0, matrix.size());
    }
};

The provided C++ code outlines a solution for constructing a quad tree from a given 2D matrix. This code effectively decomposes the matrix into submatrices until each element is individually represented in the quad tree, maintaining the groupings where possible. Here’s a breakdown of the program's functionality:

  • Node Structure: A custom node class Node is likely used, which should include properties like the node's value (val), whether it is a leaf (isLeaf), and references to its child nodes (topLeft, topRight, bottomLeft, bottomRight).

  • Function constructSubtree():

    • This recursively generates the tree.
    • Base case: If the current submatrix length (len) is 1, creates a new node that directly represents the value of the matrix at that point.
    • Recursive division: If len is greater than 1, the matrix is split into four equal parts:
      • Top left
      • Top right
      • Bottom left
      • Bottom right
    • Each quadrant is processed through recursive calls with halved length.
    • After processing, if all four nodes are leaves and contain same value, they are merged into a single node. Otherwise, the node representing current quadrant is set as an internal node linking all four child areas.
  • Function build():

    • Acts as an initial trigger for constructSubtree() function, covering the entire matrix size.

This approach is efficient in reducing the complexity of the data when uniform regions are present in the matrix, thereby significantly compressing the data size when possible. Ensure your implementations of Node and other system specifics adhere closely to what is described to ensure seamless functionality and accurate tree creation.

java
class Solution {
    private Node processGrid(int[][] matrix, int topLeftX, int topLeftY, int size) {
        if (size == 1) {
            return new Node(matrix[topLeftX][topLeftY] == 1, true);
        }

        Node tl = processGrid(matrix, topLeftX, topLeftY, size / 2);
        Node tr = processGrid(matrix, topLeftX, topLeftY + size / 2, size / 2);
        Node bl = processGrid(matrix, topLeftX + size / 2, topLeftY, size / 2);
        Node br = processGrid(matrix, topLeftX + size / 2, topLeftY + size / 2, size / 2);

        if (tl.isLeaf && tr.isLeaf && bl.isLeaf && br.isLeaf
            && tl.val == tr.val && tr.val == bl.val && bl.val == br.val) {
            return new Node(tl.val, true);
        }

        return new Node(false, false, tl, tr, bl, br);
    }

    public Node construct(int[][] matrix) {
        return processGrid(matrix, 0, 0, matrix.length);
    }
}

The Java solution provided is an implementation of constructing a Quad Tree from a 2D matrix. The Quad Tree is a type of data structure suitable for managing hierarchical spatial data. Each node in this tree can either store a single value if it's a leaf node, or it can link to four children representing the subdivisions of the area that the node covers.

To implement this, the solution defines a recursive method processGrid which checks if the current part of the matrix it's examining is uniform in value. Here's how it operates:

  • Base Case: If the subdivided region is a single element (size == 1), it returns a leaf node with the value set to the element's value (either true if 1 or false if 0).
  • Recursive Case: The method splits the region into four equal parts and processes each part:
    • Top-left (tl)
    • Top-right (tr)
    • Bottom-left (bl)
    • Bottom-right (br)
  • After recursive division, if all four parts are leaf nodes and have the same boolean value, those parts are consolidated into a single leaf node representing that larger area. If the values differ, it creates a parent node with those four parts as children but sets the node as non-leaf.

The main construct method serves as an entry point that initiates the recursion from the top level of the matrix spanning its entire dimension.

This efficient Quad Tree building process divides the data until all minimum units (matrix elements) are processed, either creating leaf nodes for homogeneous areas or parent nodes for mixed data, providing effective spatial decomposition that can be essential for applications like image processing or spatial analysis.

Comments

No comments yet.