Size of all Connected Non-Empty Cells of a Matrix


In this problem, we will find the size of sets of all non−empty connected cells.

We will learn two different approaches for finding the size of all non−empty connected cells of a matrix. In the first approach, we will use the breadth−first search algorithm, and in the second approach, we will use the depth−first search algorithm to traverse the matrix and find the size of all non-empty connected cells.

Problem statement − We have given matrix[][] 2D array containing only 0 and 1. Here, 0 represents the empty cell, and 1 represents the non−empty cells. We need to find the size of the non−empty connected cells.

Note − We can say that two cells are connected if they are horizontally and vertically adjacent to each other.

Sample examples

Input

{{0, 1, 0, 0, 0},
{0, 1, 1, 1, 1},
{1, 0, 0, 1, 1},
{1, 0, 0, 0, 0},
{0, 0, 1, 1, 1}};

Output

7 2 3

Explanation 

  • The first connected set contains matrix[0][1], matrix[1][1], matrix[1][2], matrix[1][3], matrix[1][4], matrix[2][3], and matrix[2][4] cells.

  • The second connected set contains the matrix[2][0], and matrix[3][0] cells.

  • The third connected set contains the matrix[4][2], matrix[4][3], and matrix[4][4] cells.

Input

{{0, 1, 0, 0, 0},
{0, 1, 1, 1, 1},
{0, 0, 0, 1, 1},
{0, 0, 0, 1, 0},
{0, 0, 1, 1, 1}};

Output

11

Explanation − All non−empty cells of the matrix are connected.

Approach 1

In this approach, we will use the BFS technique to traverse each matrix cell. If we find the non−empty cell, we start BFS traversal from that cell to find the number of all connected nodes. Also, we update the visited nodes to 0, as we don’t want to calculate the same node multiple times.

Algorithm

Step 1 − Use two nested loops to traverse the matrix.

Step 2 − If the value of the current cell is 1, call the BFSTraversal() function to get the size of all connected cells to the current cell.

Step 2.1 − In the BFSTraversal() function, initialize the ‘res’ with 0 to store the size. Also, define the queue for the BFS traversal.

Step 2.2 − Insert the coordinates of the current cell into the queue

Step 2.3 − Make traversal while the queue is not empty.

Step 2.3.1 − Get the first pair from the queue inside the loop.

Step 2.3.2 − Get the row and column values from the first pair. Also, check the boundary validation to ensure the row and column pair is a valid matrix cell.

Step 2.3.3 − If matrix[row][col] is 0, continue with the next iteration of the loop. Otherwise, update the matrix[col][row] with 0, and increment the ‘res’ by 1.

Step 2.3.4 − Insert the pairs of row and col for all 4 neighbor elements into the queue.

Step 2.4 − Return the ‘res’ value.

Step 3 − Insert the returned value from the BFSTraversal() function to the ‘ans’ list.

Step 4 − Print all elements of the ‘ans’ list.

Example

#include <bits/stdc++.h>
using namespace std;

int BFSTraversal(vector<vector<int>> &matrix, int p, int q, int rows, int cols) {
    int res = 0;
    // Queue to store the cells
    queue<pair<int, int>> que;
    // Insert the starting point
    que.push({p, q});
    while (!que.empty()) {
        // Get the first element from the queue
        auto first = que.front();
        que.pop();
        int row = first.first, col = first.second;
        // Boundry validation
        if (row < 0 || col < 0 || row > rows - 1 || col > cols - 1)
            continue;
        // For visited elements
        if (matrix[row][col] == 0)
            continue;
        // For non-visited elements
        if (matrix[row][col] == 1) {
            // Update matrix cell
            matrix[row][col] = 0;
            res++;
        }
        // Traverse all neighbors
        que.push({row + 1, col});
        que.push({row - 1, col});
        que.push({row, col + 1});
        que.push({row, col - 1});
    }
    return res;
}
void printSizeOfConnected(vector<vector<int>> matrix) {
    // To store sizes
    vector<int> ans;
    int rows = matrix.size();
    int cols = matrix[0].size();
    for (int p = 0; p < rows; ++p) {
        for (int q = 0; q < cols; ++q) {
            // If the current cell is not visited
            if (matrix[p][q] == 1) {
                // To get the total number of connected nodes to the current node
                int sz = BFSTraversal(matrix, p, q, rows, cols);
                ans.push_back(sz);
            }
        }
    }
    cout << "The sizes of the connected nodes are ";
    for (int val : ans)
        cout << val << " ";
}
int main() {
    vector<vector<int>> matrix = {{0, 1, 0, 0, 0},
                                  {0, 1, 1, 1, 1},
                                  {1, 0, 0, 1, 1},
                                  {1, 0, 0, 0, 0},
                                  {0, 0, 1, 1, 1}};

    printSizeOfConnected(matrix);
    return 0;
}

Output

The sizes of the connected nodes are 7 2 3

Time complexity − O(row*col) to traverse all cells of the matrix.

Space complexity − O(row*col) to store pairs in the queue.

Approach 2

We will use the DFS traversal in this approach to find the size of the non−empty connected cells.

Algorithm

Step 1 − Define the ‘vis’ list to track whether the particular cell of the matrix is visited.

Step 2 − Start traversing the matrix using two nested loops.

Step 3 − If the cell value is 1 and not visited, call the performDFS() function to find the size of the connected non−empty set.

Step 3.1 − In the performDFS() function, update the vis[p][q] with 1, and increment the ‘sz’ by 1.

Step 3.2 − Define the dirX[] and dirY[] array containing vertical and horizontal directions.

Step 3.3 − Start traversing the dirX[] and dirY[] array to move in each direction.

Step 3.4 − Check for the updated row and column value boundary validation. Also, the cell value is 1, and is not visited, so execute the performDFS() function for updated coordinates.

Step 4 − Print the ‘sz’ value.

Example

#include <bits/stdc++.h>
using namespace std;

void performDFS(vector<vector<int>> &matrix, vector<vector<int>> &vis, int p, int q, int *sz) {
    // Current node is visited
    vis[p][q] = 1;
    (*sz)++;
    int dirX[] = {-1, 0, 1, 0};
    int dirY[] = {0, 1, 0, -1};
    // Traverse in all adjacent directions
    for (int k = 0; k < 4; k++) {
        int temp1 = p + dirX[k];
        int temp2 = q + dirY[k];
        // Validating the boundary conditions and checking if the current cell is non-visited
        if (temp1 >= 0 && temp1 < matrix.size() && temp2 >= 0 && temp2 < matrix[0].size() && matrix[temp1][temp2] && !vis[temp1][temp2]) {
            // Making recursive calls for all nodes
            performDFS(matrix, vis, temp1, temp2, sz);
        }
    }
}
int main() {
    vector<vector<int>> matrix = {
        {1, 0, 1, 0},
        {1, 0, 0, 1},
        {0, 1, 0, 0},
        {1, 1, 0, 1}};
    int rows = matrix.size();
    int cols = matrix[0].size();
    vector<vector<int>> vis(rows, vector<int>(cols, 0));
    cout << "The sizes of the connected nodes are ";
    // Traverse the matrix and count the size of each connected component
    for (int p = 0; p < rows; p++) {
        for (int q = 0; q < cols; q++) {
            if (matrix[p][q] && !vis[p][q]) {
                int sz = 0;
                performDFS(matrix, vis, p, q, &sz);
                cout << sz << " ";
            }
        }
    }
    return 0;
}

Output

The sizes of the connected nodes are 2 1 1 3 1

Time complexity − O(row*col)

Space complexity − O(1)

The BFS and DFS traversal gives the same result. However, DFS traversal doesn’t take the dynamic memory. Whenever programmers need to find the shortest path or something like that, it is recommended to use the BFS traversal. Otherwise, programmers can use any of BFS or DFS traversal.

Updated on: 02-Aug-2023

65 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements