Count Groups of 1s Surrounded by 0s

Last Updated : 17 Oct, 2026

Given a binary matrix mat[][] of size n x m, where 1 represents an active cell and 0 represents an inactive cell, count the number of groups of connected 1s that are completely surrounded by 0s.

Two 1 cells are considered connected if they share a side (up, down, left, or right).

A group is counted only if none of its cells lie on the boundary of the matrix.

Examples:

Input: mat[][] = [[0, 0, 0, 0, 0], [0, 1, 0, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
Output: 1
Explanation:

12

There is 1 group of connected 1s that is completely surrounded by 0s and does not touch the boundary, so the answer is 1. The 1 on the boundary is not counted.

Input: mat[][] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
Output: 1
Explanation:

11

Only the cell at the center forms a valid group because it does not touch the boundary and is surrounded by 0s. The other 1s lie on the boundary of the matrix, so they are not counted.

Try It Yourself
redirect icon

DFS Traversal in Two Pass- O(n * m) and O(n * m) Space

First, we traverse all the boundary cells of the matrix. If a boundary cell contains 1, we perform DFS from that cell and mark all connected 1s as visited/

After marking all boundary-connected groups, we traverse the entire matrix again. For every unvisited 1, we perform DFS to explore its connected group. Each such DFS represents one group of surrounded 1s, so we increment the count.

C++
#include <iostream>
#include <vector>
using namespace std;

// DFS to mark all connected land cells as visited
void dfs(vector<vector<int>> &matrix, vector<vector<bool>> &visited, 
int x, int y, int n, int m)
{

    if (x < 0 || y < 0 || x >= n || y >= m || visited[x][y] 
    || matrix[x][y] == 0)
        return;

    visited[x][y] = true;

    // Traverse to all adjacent elements
    dfs(matrix, visited, x + 1, y, n, m);
    dfs(matrix, visited, x - 1, y, n, m);
    dfs(matrix, visited, x, y + 1, n, m);
    dfs(matrix, visited, x, y - 1, n, m);
}

// Count the groups of surrounded 1s
int countGroups(vector<vector<int>> &matrix)
{

    int n = matrix.size(), m = matrix[0].size();
    vector<vector<bool>> visited(n, vector<bool>(m, false));

    // Mark groups connected to the boundary
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {

            // Check it is boundary and not visited
            if ((i * j == 0 || i == n - 1 || j == m - 1) && matrix[i][j] == 1 && !visited[i][j])
            {
                dfs(matrix, visited, i, j, n, m);
            }
        }
    }

    int res = 0;

    // Count remaining unvisited groups of surrounded 1s
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {
            if (matrix[i][j] == 1 && !visited[i][j])
            {
                res++;
                dfs(matrix, visited, i, j, n, m);
            }
        }
    }

    return res;
}

int main()
{
    vector<vector<int>> matrix = {{0, 0, 0, 0, 0}, {0, 1, 0, 1, 0}, {0, 1, 1, 1, 0}, {0, 0, 0, 0, 1}};

    cout << countGroups(matrix);
    return 0;
}
Java
import java.util.Arrays;

public class GFG {
    // DFS to mark all connected land cells as visited
    public static void dfs(int[][] matrix,
                           boolean[][] visited, int x,
                           int y, int n, int m)
    {
        if (x < 0 || y < 0 || x >= n || y >= m
            || visited[x][y] || matrix[x][y] == 0)
            return;

        visited[x][y] = true;

        // Traverse to all adjacent elements
        dfs(matrix, visited, x + 1, y, n, m);
        dfs(matrix, visited, x - 1, y, n, m);
        dfs(matrix, visited, x, y + 1, n, m);
        dfs(matrix, visited, x, y - 1, n, m);
    }

    // Count the groups of surrounded 1s
    public static int countGroups(int[][] matrix)
    {
        int n = matrix.length, m = matrix[0].length;
        boolean[][] visited = new boolean[n][m];

        // Mark groups connected to the boundary
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                // Check it is boundary and not visited
                if ((i * j == 0 || i == n - 1 || j == m - 1)
                    && matrix[i][j] == 1
                    && !visited[i][j]) {
                    dfs(matrix, visited, i, j, n, m);
                }
            }
        }

        int res = 0;

        // Count remaining unvisited groups of surrounded 1s
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (matrix[i][j] == 1 && !visited[i][j]) {
                    res++;
                    dfs(matrix, visited, i, j, n, m);
                }
            }
        }

        return res;
    }

    public static void main(String[] args)
    {
        int[][] matrix = { { 0, 0, 0, 0, 0 },
                           { 0, 1, 0, 1, 0 },
                           { 0, 1, 1, 1, 0 },
                           { 0, 0, 0, 0, 1 } };
        System.out.println(countGroups(matrix));
    }
}
Python
def dfs(matrix, visited, x, y, n, m):
    if x < 0 or y < 0 or x >= n or y >= m or visited[x][y] or matrix[x][y] == 0:
        return

    visited[x][y] = True

    # Traverse to all adjacent elements
    dfs(matrix, visited, x + 1, y, n, m)
    dfs(matrix, visited, x - 1, y, n, m)
    dfs(matrix, visited, x, y + 1, n, m)
    dfs(matrix, visited, x, y - 1, n, m)

def countGroups(matrix):
    n = len(matrix)
    m = len(matrix[0])
    visited = [[False for _ in range(m)] for _ in range(n)]

    # Mark groups connected to the boundary
    for i in range(n):
        for j in range(m):
            # Check it is boundary and not visited
            if (i * j == 0 or i == n - 1 or j == m - 1) and matrix[i][j] == 1 and not visited[i][j]:
                dfs(matrix, visited, i, j, n, m)

    res = 0

    # Count remaining unvisited groups of surrounded 1s
    for i in range(n):
        for j in range(m):
            if matrix[i][j] == 1 and not visited[i][j]:
                res += 1
                dfs(matrix, visited, i, j, n, m)

    return res


if __name__ == "__main__":
    matrix = [
        [0, 0, 0, 0, 0],
        [0, 1, 0, 1, 0],
        [0, 1, 1, 1, 0],
        [0, 0, 0, 0, 1]
    ]

    print(countGroups(matrix))
C#
using System;

class GFG {
    // DFS to mark all connected 1s as visited
    static void Dfs(int[][] matrix, bool[][] visited, int x,
                    int y, int n, int m)
    {
        if (x < 0 || y < 0 || x >= n || y >= m
            || visited[x][y] || matrix[x][y] == 0)
            return;

        visited[x][y] = true;

        // Traverse to all adjacent elements
        Dfs(matrix, visited, x + 1, y, n, m);
        Dfs(matrix, visited, x - 1, y, n, m);
        Dfs(matrix, visited, x, y + 1, n, m);
        Dfs(matrix, visited, x, y - 1, n, m);
    }

    // Count the groups of surrounded 1s
    static int countGroups(int[][] matrix)
    {
        int n = matrix.Length;
        int m = matrix[0].Length;

        bool[][] visited = new bool[n][];

        for (int i = 0; i < n; i++)
            visited[i] = new bool[m];

        // Mark groups connected to the boundary
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                // Check it is boundary and not visited
                if ((i == 0 || j == 0 || i == n - 1
                     || j == m - 1)
                    && matrix[i][j] == 1
                    && !visited[i][j]) {
                    Dfs(matrix, visited, i, j, n, m);
                }
            }
        }

        int res = 0;

        // Count remaining unvisited groups of surrounded 1s
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (matrix[i][j] == 1 && !visited[i][j]) {
                    res++;
                    Dfs(matrix, visited, i, j, n, m);
                }
            }
        }

        return res;
    }

    static int Main()
    {
        int[][] matrix
            = new int[][] { new int[] { 0, 0, 0, 0, 0 },
                            new int[] { 0, 1, 0, 1, 0 },
                            new int[] { 0, 1, 1, 1, 0 },
                            new int[] { 0, 0, 0, 0, 1 } };

        Console.WriteLine(countGroups(matrix));

        return 0;
    }
}
JavaScript
function dfs(matrix, visited, x, y, n, m)
{
    if (x < 0 || y < 0 || x >= n || y >= m || visited[x][y]
        || matrix[x][y] === 0)
        return;

    visited[x][y] = true;

    // Traverse to all adjacent elements
    dfs(matrix, visited, x + 1, y, n, m);
    dfs(matrix, visited, x - 1, y, n, m);
    dfs(matrix, visited, x, y + 1, n, m);
    dfs(matrix, visited, x, y - 1, n, m);
}

function countGroups(matrix)
{
    let n = matrix.length, m = matrix[0].length;
    let visited = Array.from({length : n},
                             () => Array(m).fill(false));

    // Mark groups connected to the boundary
    for (let i = 0; i < n; ++i) {
        for (let j = 0; j < m; ++j) {
            // Check it is boundary and not visited
            if ((i * j === 0 || i === n - 1 || j === m - 1)
                && matrix[i][j] === 1 && !visited[i][j]) {
                dfs(matrix, visited, i, j, n, m);
            }
        }
    }

    let res = 0;

    // Count remaining unvisited groups of surrounded 1s
    for (let i = 0; i < n; ++i) {
        for (let j = 0; j < m; ++j) {
            if (matrix[i][j] === 1 && !visited[i][j]) {
                res++;
                dfs(matrix, visited, i, j, n, m);
            }
        }
    }

    return res;
}

// Driver Code
let matrix = [
    [ 0, 0, 0, 0, 0 ], [ 0, 1, 0, 1, 0 ], [ 0, 1, 1, 1, 0 ],
    [ 0, 0, 0, 0, 1 ]
];
console.log(countGroups(matrix));

Output
1

DFS Traversal in One Pass – O(n * m) Time and O(n * m) Space

Instead of performing two separate DFS traversals, we perform a single DFS from each unvisited 1 cell. We maintain a boolean variable hasBoundary to track whether the current group of 1s touches the boundary.

During DFS, if any 1 cell lies on the boundary, we set hasBoundary to true. After the DFS completes, if hasBoundary is false, the group does not touch the boundary, so we count it as a group of surrounded 1s.

C++
#include <iostream>
#include <vector>
using namespace std;

// DFS to mark all connected land cells as visited
void dfs(vector<vector<int>> &matrix, vector<vector<bool>> &visited, int x, int y, int n, int m,
         bool &hasBoundary)
{

    // Base case
    if (x < 0 || y < 0 || x >= n || y >= m || visited[x][y] || matrix[x][y] == 0)
        return;

    // Mark if the current land cell lies on the boundary
    if (x == 0 || y == 0 || x == n - 1 || y == m - 1)
        hasBoundary = true;

    visited[x][y] = true;

    // Explore all 4 directions
    dfs(matrix, visited, x + 1, y, n, m, hasBoundary);
    dfs(matrix, visited, x - 1, y, n, m, hasBoundary);
    dfs(matrix, visited, x, y + 1, n, m, hasBoundary);
    dfs(matrix, visited, x, y - 1, n, m, hasBoundary);
}

// Count the groups of surrounded 1s
int countGroups(vector<vector<int>> &matrix)
{
    int n = matrix.size(), m = matrix[0].size();
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    int res = 0;

    // Start DFS for land cells
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {

            // Check it is land cell and not visited
            if (matrix[i][j] == 1 && !visited[i][j])
            {
                bool hasBoundary = false;
                dfs(matrix, visited, i, j, n, m, hasBoundary);

                // Count only if not touching boundary
                if (!hasBoundary)
                    res++;
            }
        }
    }
    return res;
}

int main()
{
    vector<vector<int>> matrix = {{0, 0, 0, 0, 0}, {0, 1, 0, 1, 0}, {0, 1, 1, 1, 0}, {0, 0, 0, 0, 1}};

    cout << countGroups(matrix);
    return 0;
}
Java
import java.util.Arrays;

public class GFG {
    // DFS to mark all connected land cells as visited
    public static void dfs(int[][] matrix,
                           boolean[][] visited, int x,
                           int y, int n, int m,
                           boolean[] hasBoundary)
    {
        // Base case
        if (x < 0 || y < 0 || x >= n || y >= m
            || visited[x][y] || matrix[x][y] == 0)
            return;

        // Mark if the current land cell lies on the
        // boundary
        if (x == 0 || y == 0 || x == n - 1 || y == m - 1)
            hasBoundary[0] = true;

        visited[x][y] = true;

        // Explore all 4 directions
        dfs(matrix, visited, x + 1, y, n, m, hasBoundary);
        dfs(matrix, visited, x - 1, y, n, m, hasBoundary);
        dfs(matrix, visited, x, y + 1, n, m, hasBoundary);
        dfs(matrix, visited, x, y - 1, n, m, hasBoundary);
    }

    // Count the groups of surrounded 1s
    public static int countGroups(int[][] matrix)
    {
        int n = matrix.length, m = matrix[0].length;
        boolean[][] visited = new boolean[n][m];
        int res = 0;

        // Start DFS for land cells
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                // Check it is land cell and not visited
                if (matrix[i][j] == 1 && !visited[i][j]) {
                    boolean[] hasBoundary = { false };
                    dfs(matrix, visited, i, j, n, m,
                        hasBoundary);

                    // Count only if not touching boundary
                    if (!hasBoundary[0])
                        res++;
                }
            }
        }
        return res;
    }

    public static void main(String[] args)
    {
        int[][] matrix = { { 0, 0, 0, 0, 0 },
                           { 0, 1, 0, 1, 0 },
                           { 0, 1, 1, 1, 0 },
                           { 0, 0, 0, 0, 1 } };

        System.out.println(countGroups(matrix));
    }
}
Python
def dfs(matrix, visited, x, y, n, m, hasBoundary):
    # Base case
    if x < 0 or y < 0 or x >= n or y >= m or visited[x][y] or matrix[x][y] == 0:
        return

    # Mark if the current land cell lies on the boundary
    if x == 0 or y == 0 or x == n - 1 or y == m - 1:
        hasBoundary[0] = True

    visited[x][y] = True

    # Explore all 4 directions
    dfs(matrix, visited, x + 1, y, n, m, hasBoundary)
    dfs(matrix, visited, x - 1, y, n, m, hasBoundary)
    dfs(matrix, visited, x, y + 1, n, m, hasBoundary)
    dfs(matrix, visited, x, y - 1, n, m, hasBoundary)


def countGroups(matrix):
    n = len(matrix)
    m = len(matrix[0])
    visited = [[False] * m for _ in range(n)]
    res = 0

    # Start DFS for land cells
    for i in range(n):
        for j in range(m):
            # Check it is land cell and not visited
            if matrix[i][j] == 1 and not visited[i][j]:
                hasBoundary = [False]
                dfs(matrix, visited, i, j, n, m, hasBoundary)

                # Count only if not touching boundary
                if not hasBoundary[0]:
                    res += 1
    return res


if __name__ == '__main__':
    matrix = [[0, 0, 0, 0, 0], [0, 1, 0, 1, 0],
              [0, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
    print(countGroups(matrix))
C#
using System;

public class GFG {
    // DFS to mark all connected 1s as visited
    public static void dfs(int[][] matrix, bool[][] visited,
                           int x, int y, int n, int m,
                           ref bool hasBoundary)
    {
        // Base case
        if (x < 0 || y < 0 || x >= n || y >= m
            || visited[x][y] || matrix[x][y] == 0)
            return;

        // Mark if the current 1 lies on the boundary
        if (x == 0 || y == 0 || x == n - 1 || y == m - 1)
            hasBoundary = true;

        visited[x][y] = true;

        // Explore all 4 directions
        dfs(matrix, visited, x + 1, y, n, m,
            ref hasBoundary);
        dfs(matrix, visited, x - 1, y, n, m,
            ref hasBoundary);
        dfs(matrix, visited, x, y + 1, n, m,
            ref hasBoundary);
        dfs(matrix, visited, x, y - 1, n, m,
            ref hasBoundary);
    }

    // Count the groups of surrounded 1s
    public static int countGroups(int[][] matrix)
    {
        int n = matrix.Length;
        int m = matrix[0].Length;

        bool[][] visited = new bool[n][];

        for (int i = 0; i < n; i++)
            visited[i] = new bool[m];

        int res = 0;

        // Start DFS for each unvisited 1
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                // Check it is a 1 and not visited
                if (matrix[i][j] == 1 && !visited[i][j]) {
                    bool hasBoundary = false;

                    dfs(matrix, visited, i, j, n, m,
                        ref hasBoundary);

                    // Count only if not touching boundary
                    if (!hasBoundary)
                        res++;
                }
            }
        }

        return res;
    }

    public static int Main()
    {
        int[][] matrix
            = new int[][] { new int[] { 0, 0, 0, 0, 0 },
                            new int[] { 0, 1, 0, 1, 0 },
                            new int[] { 0, 1, 1, 1, 0 },
                            new int[] { 0, 0, 0, 0, 1 } };

        Console.WriteLine(countGroups(matrix));

        return 0;
    }
}
JavaScript
function dfs(matrix, visited, x, y, n, m, hasBoundary)
{
    // Base case
    if (x < 0 || y < 0 || x >= n || y >= m || visited[x][y]
        || matrix[x][y] === 0)
        return;

    // Mark if the current land cell lies on the boundary
    if (x === 0 || y === 0 || x === n - 1 || y === m - 1)
        hasBoundary[0] = true;

    visited[x][y] = true;

    // Explore all 4 directions
    dfs(matrix, visited, x + 1, y, n, m, hasBoundary);
    dfs(matrix, visited, x - 1, y, n, m, hasBoundary);
    dfs(matrix, visited, x, y + 1, n, m, hasBoundary);
    dfs(matrix, visited, x, y - 1, n, m, hasBoundary);
}

function countGroups(matrix)
{
    const n = matrix.length;
    const m = matrix[0].length;
    const visited = Array.from({length : n},
                               () => Array(m).fill(false));
    let res = 0;

    // Start DFS for land cells
    for (let i = 0; i < n; ++i) {
        for (let j = 0; j < m; ++j) {
            // Check it is land cell and not visited
            if (matrix[i][j] === 1 && !visited[i][j]) {
                const hasBoundary = [ false ];
                dfs(matrix, visited, i, j, n, m,
                    hasBoundary);

                // Count only if not touching boundary
                if (!hasBoundary[0])
                    res++;
            }
        }
    }
    return res;
}

// Driver Code
const matrix = [
    [ 0, 0, 0, 0, 0 ], [ 0, 1, 0, 1, 0 ], [ 0, 1, 1, 1, 0 ],
    [ 0, 0, 0, 0, 1 ]
];
console.log(countGroups(matrix));

Output
1

BFS Traversal – O(n * m) Time and O(n * m) Space

The idea is similar to the DFS-based approach, but here we use Breadth-First Search (BFS) instead of DFS to count the number of groups of surrounded 1s.

C++
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

// BFS to mark all connected 1s as visited
void dfs(vector<vector<int>> &matrix, vector<vector<bool>> &visited, int x, int y, int n, int m,
         bool &hasBoundary)
{

    queue<pair<int, int>> q;
    q.push({x, y});
    visited[x][y] = true;

    // Directions: down, up, right, left
    int dx[] = {1, -1, 0, 0};
    int dy[] = {0, 0, 1, -1};

    while (!q.empty())
    {
        auto [cx, cy] = q.front();
        q.pop();

        // Check if the current 1 lies on the boundary
        if (cx == 0 || cy == 0 || cx == n - 1 || cy == m - 1)
            hasBoundary = true;

        // Explore all four adjacent cells
        for (int dir = 0; dir < 4; ++dir)
        {
            int nx = cx + dx[dir];
            int ny = cy + dy[dir];

            // Check valid, unvisited, and connected 1
            if (nx >= 0 && ny >= 0 && nx < n && ny < m && !visited[nx][ny] && matrix[nx][ny] == 1)
            {
                visited[nx][ny] = true;
                q.push({nx, ny});
            }
        }
    }
}

// Count the groups of surrounded 1s
int countGroups(vector<vector<int>> &matrix)
{
    int n = matrix.size(), m = matrix[0].size();
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    int res = 0;

    // Start BFS for each unvisited 1
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {

            // Check if the cell is a 1 and not visited
            if (matrix[i][j] == 1 && !visited[i][j])
            {
                bool hasBoundary = false;
                dfs(matrix, visited, i, j, n, m, hasBoundary);

                // Count only groups that do not touch the boundary
                if (!hasBoundary)
                    res++;
            }
        }
    }

    return res;
}

int main()
{

    vector<vector<int>> mat = {{0, 0, 0, 0, 0}, {0, 1, 0, 1, 0}, {0, 1, 1, 1, 0}, {0, 0, 0, 0, 1}};

    cout << countGroups(mat);

    return 0;
}
Java
import java.util.LinkedList;
import java.util.Queue;

class GFG {
    // BFS to mark all connected 1s as visited
    static void dfs(int[][] matrix, boolean[][] visited,
                    int x, int y, int n, int m,
                    boolean[] hasBoundary)
    {
        Queue<int[]> q = new LinkedList<>();
        q.add(new int[] { x, y });
        visited[x][y] = true;

        // Directions: down, up, right, left
        int[] dx = { 1, -1, 0, 0 };
        int[] dy = { 0, 0, 1, -1 };

        while (!q.isEmpty()) {
            int[] cur = q.poll();
            int cx = cur[0];
            int cy = cur[1];

            // Check if the current 1 lies on the boundary
            if (cx == 0 || cy == 0 || cx == n - 1
                || cy == m - 1)
                hasBoundary[0] = true;

            // Explore all four adjacent cells
            for (int dir = 0; dir < 4; ++dir) {
                int nx = cx + dx[dir];
                int ny = cy + dy[dir];

                // Check valid, unvisited, and connected 1
                if (nx >= 0 && ny >= 0 && nx < n && ny < m
                    && !visited[nx][ny]
                    && matrix[nx][ny] == 1) {
                    visited[nx][ny] = true;
                    q.add(new int[] { nx, ny });
                }
            }
        }
    }

    // Count the groups of surrounded 1s
    static int countGroups(int[][] matrix)
    {
        int n = matrix.length, m = matrix[0].length;
        boolean[][] visited = new boolean[n][m];
        int res = 0;

        // Start BFS for each unvisited 1
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {

                // Check if the cell is a 1 and not visited
                if (matrix[i][j] == 1 && !visited[i][j]) {
                    boolean[] hasBoundary = { false };
                    dfs(matrix, visited, i, j, n, m,
                        hasBoundary);

                    // Count only groups that do not touch
                    // the boundary
                    if (!hasBoundary[0])
                        res++;
                }
            }
        }

        return res;
    }

    public static void main(String[] args)
    {
        int[][] mat = { { 0, 0, 0, 0, 0 },
                        { 0, 1, 0, 1, 0 },
                        { 0, 1, 1, 1, 0 },
                        { 0, 0, 0, 0, 1 } };

        System.out.println(countGroups(mat));
    }
}
Python
from collections import deque

# BFS to mark all connected 1s as visited
def dfs(matrix, visited, x, y, n, m, hasBoundary):
    q = deque([(x, y)])
    visited[x][y] = True

    # Directions: down, up, right, left
    dx = [1, -1, 0, 0]
    dy = [0, 0, 1, -1]

    while q:
        cx, cy = q.popleft()

        # Check if the current 1 lies on the boundary
        if cx == 0 or cy == 0 or cx == n - 1 or cy == m - 1:
            hasBoundary[0] = True

        # Explore all four adjacent cells
        for dir in range(4):
            nx = cx + dx[dir]
            ny = cy + dy[dir]

            # Check valid, unvisited, and connected 1
            if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny] and matrix[nx][ny] == 1:
                visited[nx][ny] = True
                q.append((nx, ny))

# Count the groups of surrounded 1s
def countGroups(matrix):
    n = len(matrix)
    m = len(matrix[0])
    visited = [[False] * m for _ in range(n)]
    res = 0

    # Start BFS for each unvisited 1
    for i in range(n):
        for j in range(m):
            # Check if the cell is a 1 and not visited
            if matrix[i][j] == 1 and not visited[i][j]:
                hasBoundary = [False]
                dfs(matrix, visited, i, j, n, m, hasBoundary)

                # Count only groups that do not touch the boundary
                if not hasBoundary[0]:
                    res += 1
    return res

if __name__ == '__main__':
    mat = [
        [0, 0, 0, 0, 0],
        [0, 1, 0, 1, 0],
        [0, 1, 1, 1, 0],
        [0, 0, 0, 0, 1]
    ]
    print(countGroups(mat))
C#
using System;
using System.Collections.Generic;

class GFG {
    // BFS to mark all connected 1s as visited
    static void dfs(int[][] matrix, bool[][] visited, int x,
                    int y, int n, int m,
                    ref bool hasBoundary)
    {
        Queue<(int, int)> q = new Queue<(int, int)>();
        q.Enqueue((x, y));
        visited[x][y] = true;

        // Directions: down, up, right, left
        int[] dx = { 1, -1, 0, 0 };
        int[] dy = { 0, 0, 1, -1 };

        while (q.Count > 0) {
            var(cx, cy) = q.Dequeue();

            // Check if the current 1 lies on the boundary
            if (cx == 0 || cy == 0 || cx == n - 1
                || cy == m - 1)
                hasBoundary = true;

            // Explore all four adjacent cells
            for (int dir = 0; dir < 4; ++dir) {
                int nx = cx + dx[dir];
                int ny = cy + dy[dir];

                // Check valid, unvisited, and connected 1
                if (nx >= 0 && ny >= 0 && nx < n && ny < m
                    && !visited[nx][ny]
                    && matrix[nx][ny] == 1) {
                    visited[nx][ny] = true;
                    q.Enqueue((nx, ny));
                }
            }
        }
    }

    // Count the groups of surrounded 1s
    static int countGroups(int[][] matrix)
    {
        int n = matrix.Length, m = matrix[0].Length;
        bool[][] visited = new bool[n][];
        for (int i = 0; i < n; ++i)
            visited[i] = new bool[m];
        int res = 0;

        // Start BFS for each unvisited 1
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                // Check if the cell is a 1 and not visited
                if (matrix[i][j] == 1 && !visited[i][j]) {
                    bool hasBoundary = false;
                    dfs(matrix, visited, i, j, n, m,
                        ref hasBoundary);

                    // Count only groups that do not touch
                    // the boundary
                    if (!hasBoundary)
                        res++;
                }
            }
        }

        return res;
    }

    static void Main(string[] args)
    {
        int[][] mat
            = new int[][] { new int[] { 0, 0, 0, 0, 0 },
                            new int[] { 0, 1, 0, 1, 0 },
                            new int[] { 0, 1, 1, 1, 0 },
                            new int[] { 0, 0, 0, 0, 1 } };

        Console.WriteLine(countGroups(mat));
    }
}
JavaScript
// BFS to mark all connected 1s as visited
function bfs(matrix, visited, x, y, n, m, hasBoundary)
{

    let q = [ [ x, y ] ];
    visited[x][y] = true;

    // Directions: down, up, right, left
    let dx = [ 1, -1, 0, 0 ];
    let dy = [ 0, 0, 1, -1 ];

    while (q.length > 0) {
        let [cx, cy] = q.shift();

        // Check if the current 1 lies on the boundary
        if (cx === 0 || cy === 0 || cx === n - 1
            || cy === m - 1)
            hasBoundary.value = true;

        // Explore all four adjacent cells
        for (let dir = 0; dir < 4; dir++) {
            let nx = cx + dx[dir];
            let ny = cy + dy[dir];

            // Check valid, unvisited, and connected 1
            if (nx >= 0 && ny >= 0 && nx < n && ny < m
                && !visited[nx][ny]
                && matrix[nx][ny] === 1) {

                visited[nx][ny] = true;
                q.push([ nx, ny ]);
            }
        }
    }
}

// Count the groups of surrounded 1s
function countGroups(matrix)
{
    let n = matrix.length;
    let m = matrix[0].length;

    let visited = Array.from({length : n},
                             () => Array(m).fill(false));
    let res = 0;

    // Start BFS for each unvisited 1
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {

            // Check if the cell is a 1 and not visited
            if (matrix[i][j] === 1 && !visited[i][j]) {

                let hasBoundary = {value : false};

                bfs(matrix, visited, i, j, n, m,
                    hasBoundary);

                // Count only groups that do not touch the
                // boundary
                if (!hasBoundary.value)
                    res++;
            }
        }
    }

    return res;
}

// Driver code
let mat = [
    [ 0, 0, 0, 0, 0 ], [ 0, 1, 0, 1, 0 ], [ 0, 1, 1, 1, 0 ],
    [ 0, 0, 0, 0, 1 ]
];

console.log(countGroups(mat));

Output
1

Disjoint-Set ( Union-Find ) – O(n * m) Time and O(n * m) Space

The main idea is to use the Disjoint Set Union (DSU). Each 1 cell is treated as a node, and adjacent 1 cells are joined into the same set using union operations.

  • First, groups of 1s connected to the boundary are removed, since they cannot be completely surrounded by 0s.
  • After processing the remaining cells, the number of distinct sets gives the total number of groups of surrounded 1s.
C++
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;

vector<int> parent;

// Find the root of a node
int find(int x)
{
    if (parent[x] == x)
        return x;

    return parent[x] = find(parent[x]);
}

// Union two sets
void unionFind(int a, int b)
{
    int rootA = find(a);
    int rootB = find(b);

    if (rootA != rootB)
        parent[rootA] = rootB;
}

// DFS to mark all boundary-connected land cells as water
void floodFill(vector<vector<int>> &mat, int x, int y, int n, int m)
{

    if (x < 0 || y < 0 || x >= n || y >= m || mat[x][y] == 0)
        return;

    // Mark as water
    mat[x][y] = 0;

    floodFill(mat, x + 1, y, n, m);
    floodFill(mat, x - 1, y, n, m);
    floodFill(mat, x, y + 1, n, m);
    floodFill(mat, x, y - 1, n, m);
}

// Remove all land connected to the boundary
void remBoundIs(vector<vector<int>> &mat)
{

    int n = mat.size();
    int m = mat[0].size();

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {

            // Check boundary cells
            if (i == 0 || j == 0 || i == n - 1 || j == m - 1)
            {
                if (mat[i][j] == 1)
                    floodFill(mat, i, j, n, m);
            }
        }
    }
}

// Count the groups of surrounded 1s
int countGroups(vector<vector<int>> &mat)
{

    if (mat.empty())
        return 0;

    int n = mat.size();
    int m = mat[0].size();

    // Remove groups connected to boundary
    remBoundIs(mat);

    // Initialize DSU
    parent.resize(n * m);
    iota(parent.begin(), parent.end(), 0);

    // Connect adjacent 1s
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {

            if (mat[i][j] == 1)
            {

                int id = i * m + j;

                // Connect to right neighbor
                if (j + 1 < m && mat[i][j + 1] == 1)
                    unionFind(id, id + 1);

                // Connect to bottom neighbor
                if (i + 1 < n && mat[i + 1][j] == 1)
                    unionFind(id, id + m);
            }
        }
    }

    // Count distinct groups
    int count = 0;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {

            if (mat[i][j] == 1)
            {
                int id = i * m + j;

                if (find(id) == id)
                    count++;
            }
        }
    }

    return count;
}

int main()
{

    vector<vector<int>> mat = {{0, 0, 0, 0, 0}, {0, 1, 0, 1, 0}, {0, 1, 1, 1, 0}, {0, 0, 0, 0, 1}};

    cout << countGroups(mat);

    return 0;
}
Java
import java.util.Arrays;

public class GFG {
    static int[] parent;

    // Find the root of a node
    static int find(int x)
    {
        if (parent[x] == x)
            return x;

        return parent[x] = find(parent[x]);
    }

    // Union two sets
    static void unionFind(int a, int b)
    {
        int rootA = find(a);
        int rootB = find(b);

        if (rootA != rootB)
            parent[rootA] = rootB;
    }

    // DFS to mark all boundary-connected land cells as
    // water
    static void floodFill(int[][] mat, int x, int y, int n,
                          int m)
    {
        if (x < 0 || y < 0 || x >= n || y >= m
            || mat[x][y] == 0)
            return;

        // Mark as water
        mat[x][y] = 0;

        floodFill(mat, x + 1, y, n, m);
        floodFill(mat, x - 1, y, n, m);
        floodFill(mat, x, y + 1, n, m);
        floodFill(mat, x, y - 1, n, m);
    }

    // Remove all land connected to the boundary
    static void remBoundIs(int[][] mat)
    {
        int n = mat.length;
        int m = mat[0].length;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {

                // Check boundary cells
                if (i == 0 || j == 0 || i == n - 1
                    || j == m - 1) {
                    if (mat[i][j] == 1)
                        floodFill(mat, i, j, n, m);
                }
            }
        }
    }

    // Count the groups of surrounded 1s
    static int countGroups(int[][] mat)
    {
        if (mat.length == 0)
            return 0;

        int n = mat.length;
        int m = mat[0].length;

        // Remove groups connected to boundary
        remBoundIs(mat);

        // Initialize DSU
        parent = new int[n * m];
        for (int i = 0; i < n * m; i++) {
            parent[i] = i;
        }

        // Connect adjacent 1s
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {

                if (mat[i][j] == 1) {

                    int id = i * m + j;

                    // Connect to right neighbor
                    if (j + 1 < m && mat[i][j + 1] == 1)
                        unionFind(id, id + 1);

                    // Connect to bottom neighbor
                    if (i + 1 < n && mat[i + 1][j] == 1)
                        unionFind(id, id + m);
                }
            }
        }

        // Count distinct groups
        int count = 0;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {

                if (mat[i][j] == 1) {
                    int id = i * m + j;

                    if (find(id) == id)
                        count++;
                }
            }
        }

        return count;
    }

    public static void main(String[] args)
    {
        int[][] mat = { { 0, 0, 0, 0, 0 },
                        { 0, 1, 0, 1, 0 },
                        { 0, 1, 1, 1, 0 },
                        { 0, 0, 0, 0, 1 } };

        System.out.println(countGroups(mat));
    }
}
Python
from typing import List

parent = []

# Find the root of a node
def find(x):
    if parent[x] == x:
        return x

    parent[x] = find(parent[x])
    return parent[x]

# Union two sets
def unionFind(a, b):
    rootA = find(a)
    rootB = find(b)

    if rootA != rootB:
        parent[rootA] = rootB

# DFS to mark all boundary-connected 1s as 0
def floodFill(mat, x, y, n, m):
    if x < 0 or y < 0 or x >= n or y >= m or mat[x][y] == 0:
        return

    mat[x][y] = 0

    floodFill(mat, x + 1, y, n, m)
    floodFill(mat, x - 1, y, n, m)
    floodFill(mat, x, y + 1, n, m)
    floodFill(mat, x, y - 1, n, m)

# Remove all 1s connected to the boundary
def remBoundIs(mat):
    n = len(mat)
    m = len(mat[0])

    for i in range(n):
        for j in range(m):
            if i == 0 or j == 0 or i == n - 1 or j == m - 1:
                if mat[i][j] == 1:
                    floodFill(mat, i, j, n, m)

# Count the groups of surrounded 1s
def countGroups(mat: List[List[int]]) -> int:
    global parent

    if not mat:
        return 0

    n = len(mat)
    m = len(mat[0])

    # Remove groups connected to the boundary
    remBoundIs(mat)

    # Initialize DSU
    parent = list(range(n * m))

    # Connect adjacent 1s
    for i in range(n):
        for j in range(m):
            if mat[i][j] == 1:
                id = i * m + j

                # Connect to right neighbor
                if j + 1 < m and mat[i][j + 1] == 1:
                    unionFind(id, id + 1)

                # Connect to bottom neighbor
                if i + 1 < n and mat[i + 1][j] == 1:
                    unionFind(id, id + m)

    # Count distinct groups
    count = 0

    for i in range(n):
        for j in range(m):
            if mat[i][j] == 1:
                id = i * m + j

                if find(id) == id:
                    count += 1

    return count


if __name__ == '__main__':
    mat = [
        [0, 0, 0, 0, 0],
        [0, 1, 0, 1, 0],
        [0, 1, 1, 1, 0],
        [0, 0, 0, 0, 1]
    ]

    print(countGroups(mat))
C#
using System;

class GFG {
    static int[] parent;

    // Find the root of a node
    static int Find(int x)
    {
        if (parent[x] == x)
            return x;

        return parent[x] = Find(parent[x]);
    }

    // Union two sets
    static void UnionFind(int a, int b)
    {
        int rootA = Find(a);
        int rootB = Find(b);

        if (rootA != rootB)
            parent[rootA] = rootB;
    }

    // DFS to mark all boundary-connected 1s
    static void FloodFill(int[][] mat, int x, int y, int n,
                          int m)
    {
        if (x < 0 || y < 0 || x >= n || y >= m
            || mat[x][y] == 0)
            return;

        // Mark as 0
        mat[x][y] = 0;

        FloodFill(mat, x + 1, y, n, m);
        FloodFill(mat, x - 1, y, n, m);
        FloodFill(mat, x, y + 1, n, m);
        FloodFill(mat, x, y - 1, n, m);
    }

    // Remove all 1s connected to the boundary
    static void RemoveBoundaryGroups(int[][] mat)
    {
        int n = mat.Length;
        int m = mat[0].Length;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // Check boundary cells
                if (i == 0 || j == 0 || i == n - 1
                    || j == m - 1) {
                    if (mat[i][j] == 1)
                        FloodFill(mat, i, j, n, m);
                }
            }
        }
    }

    // Count the groups of surrounded 1s
    static int countGroups(int[][] mat)
    {
        if (mat == null || mat.Length == 0)
            return 0;

        int n = mat.Length;
        int m = mat[0].Length;

        // Remove groups connected to boundary
        RemoveBoundaryGroups(mat);

        // Initialize DSU
        parent = new int[n * m];

        for (int i = 0; i < n * m; i++)
            parent[i] = i;

        // Connect adjacent 1s
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (mat[i][j] == 1) {
                    int id = i * m + j;

                    // Connect to right neighbor
                    if (j + 1 < m && mat[i][j + 1] == 1)
                        UnionFind(id, id + 1);

                    // Connect to bottom neighbor
                    if (i + 1 < n && mat[i + 1][j] == 1)
                        UnionFind(id, id + m);
                }
            }
        }

        // Count distinct groups
        int count = 0;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (mat[i][j] == 1) {
                    int id = i * m + j;

                    if (Find(id) == id)
                        count++;
                }
            }
        }

        return count;
    }

    public static int Main()
    {
        int[][] mat = { new int[] { 0, 0, 0, 0, 0 },
                        new int[] { 0, 1, 0, 1, 0 },
                        new int[] { 0, 1, 1, 1, 0 },
                        new int[] { 0, 0, 0, 0, 1 } };

        Console.WriteLine(countGroups(mat));

        return 0;
    }
}
JavaScript
let parent = [];

// Find the root of a node
function find(x)
{
    if (parent[x] === x)
        return x;

    return parent[x] = find(parent[x]);
}

// Union two sets
function unionFind(a, b)
{
    let rootA = find(a);
    let rootB = find(b);

    if (rootA !== rootB)
        parent[rootA] = rootB;
}

// DFS to mark all boundary-connected land cells as water
function floodFill(mat, x, y, n, m)
{
    if (x < 0 || y < 0 || x >= n || y >= m
        || mat[x][y] === 0)
        return;

    // Mark as water
    mat[x][y] = 0;

    floodFill(mat, x + 1, y, n, m);
    floodFill(mat, x - 1, y, n, m);
    floodFill(mat, x, y + 1, n, m);
    floodFill(mat, x, y - 1, n, m);
}

// Remove all land connected to the boundary
function remBoundIs(mat)
{
    let n = mat.length;
    let m = mat[0].length;

    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            // Check boundary cells
            if (i === 0 || j === 0 || i === n - 1
                || j === m - 1) {
                if (mat[i][j] === 1)
                    floodFill(mat, i, j, n, m);
            }
        }
    }
}

// Count the groups of surrounded 1s
function countGroups(mat)
{
    if (mat.length === 0)
        return 0;

    let n = mat.length;
    let m = mat[0].length;

    // Remove groups connected to boundary
    remBoundIs(mat);

    // Initialize DSU
    parent
        = new Array(n * m).fill().map((_, index) => index);

    // Connect adjacent 1s
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            if (mat[i][j] === 1) {
                let id = i * m + j;

                // Connect to right neighbor
                if (j + 1 < m && mat[i][j + 1] === 1)
                    unionFind(id, id + 1);

                // Connect to bottom neighbor
                if (i + 1 < n && mat[i + 1][j] === 1)
                    unionFind(id, id + m);
            }
        }
    }

    // Count distinct groups
    let count = 0;

    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            if (mat[i][j] === 1) {
                let id = i * m + j;

                if (find(id) === id)
                    count++;
            }
        }
    }

    return count;
}

// Driver Code
let mat = [
    [ 0, 0, 0, 0, 0 ], [ 0, 1, 0, 1, 0 ], [ 0, 1, 1, 1, 0 ],
    [ 0, 0, 0, 0, 1 ]
];
console.log(countGroups(mat));

Output
1
Comment