×

Search anything:

Number of closed islands [2 solutions]

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

In this article, we have explored how to find the Number of closed islands in a graph. We have presented two approaches using the concept of BFS/ DFS and Union Find.

Pre-requisites:

Problem Statement

Given a 2-D grid consists of 0s (land) and 1s (water). An island is a maximal 4-directionally connected group of 0s and a closed island is an island totally (all left, top, right, bottom) surrounded by 1s.

Return the number of closed islands.

Example:
closedIsland-grid

Output: 2

Explanation: Here the 0s which are marked inside the box are only considered to be closed islands as they are completely surrounded by 1s and follows the rest of the conditions

Observations

So from the question and the example we can say the following:

  • we can't connect 0s or 1s diagonally in any case.
  • connection can happen only in the four fundamental directions.
  • the 0s in the border will never be an island as they are not covered by 1s from all sides.
  • the 0s joining the 0s in the border can never be a part of a closed island.

Now lets solve it.

Approach 1

In this approach we will discuss a way to solve this problem using BFS/DFS. We will follow the following steps to solve it.

  • We will start our iteration from grid[1][1] as we don't have to consider the border elements.
  • Once we encounter a 0 we will first change it to another number lets say -1 to keep track of the visited grounds.
  • Then we will change all 0s neighbors horizontally or vertically from the current ground using a recursive function.
  • The recursive function will return true if that cell is visited or if its a 1
  • If its a ground not visited then it will return false if its out of boundary.
  • Then it would change the cells value to -1 as we have visited it and then call the recursive function in all four direction.
  • Then it would return the && value of all directions.

Let's look at the code it understand it better.

#include <iostream>
#include <vector>

using namespace std;

bool isClosedIsland(vector<vector<int>> &grid, int i, int j, int r, int c)
{
    if (grid[i][j] == 1 || grid[i][j] == -1)
        return true;
    if (i <= 0 || i >= r - 1 || j <= 0 || j >= c - 1)
        return false;
    grid[i][j] = -1;

    bool top = isClosedIsland(grid, i - 1, j, r, c);    // Top
    bool bottom = isClosedIsland(grid, i + 1, j, r, c); // Bottom
    bool left = isClosedIsland(grid, i, j - 1, r, c);   // Left
    bool right = isClosedIsland(grid, i, j + 1, r, c);  // Right

    return top && bottom && left && right;
}

int closedIsland(vector<vector<int>> &grid)
{
    if (grid.size() == 0)
        return 0;
    int cnt = 0, r = grid.size(), c = grid[0].size();
    for (int i = 1; i < r - 1; i++)
    {
        for (int j = 1; j < c - 1; j++)
        {
            if (grid[i][j] == 0)
            {
                if (isClosedIsland(grid, i, j, r, c))
                {
                    cnt++;
                }
            }
        }
    }
    return cnt;
}

int main()
{
    int r, c;
    cin >> r >> c;
    vector<vector<int>> grid(r, vector<int>(c));
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            cin >> grid[i][j];
        }
    }
    cout << closedIsland(grid) << endl;
    return 0;
}

The time and space complexity of the above approach will be O(r*c), where r is the number of rows and c is the number of columns in the matrix.

Approach 2

Here in this approach we will taking an insightful approach using union find.

First we would accept the vector and then numIslands() is called. Inside numsIsland first we will make all the lands or 0s in the border, and the ones having connection to those in horizontal and vertical direction of the grid will be converted to 1s or any other number as you wish. We will be doing this with changeCorner() and recursively calling change() inside it. The reason why we are doing this is in the observation section, ie, those elements will never be a part of a closed island. So the remaining zeros after this step will be a part of a closed island or itself be one.

closedIsland-2

So after this we will initialize a vector of pairs edges, we will use this to store all the connections a particular ground or 0 have with adjacent cells in right and downward direction.
Now we will iterate through the grid again, this time when we encounter a 0 we will calculate a unique id for that cell using the formula i*n+j and will check if the cells in both direction are 0s or not, if its there then we will calculate an id for both of them and will push id, right_id and id, down_id into the vector. For the above grid the following will be the edges vector.

                                1 1 1 1 1 1 1 1               9  10
                                1 0 0 0 0 1 1 1               9  17
                                1 0 1 0 1 1 1 1    --->      10  11
                                1 0 0 0 0 1 0 1              11  12
                                1 1 1 1 1 1 1 1              11  19
                                                             17  25
                                                             19  27
                                                             25  26
                                                             26  27
                                                             27  28

Now we will form another vector of size r*c where r and c are the rows and columns of the grid. This vector would act as a hash vector, so we will call it a hashSet. We will initialize the value of hashSet with the values of i. Then we will iterate through the edges vector and use Union() for each of the pair. In Union() we will use find() for each element in the pair. The find() uses the passed value and the hashSet to find the root or starting of the island chain. If the value and the hashSet value are equal then it would return the same value else it uses the while() loop to find the starting of the chain. If the root value of both the edges are different then we change the values in the hashSet, this is done from the Union() itself, since they are adjacent and part of the same chain. By the end of this step the starting node id's index inside the hashSet will have same value as its index and the rest of them will have the index value of other nodes which would connect them with these starting nodes. The following is the hashSet value for the given grid.

0 1 2 3 4 5 6 7 8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
0 1 2 3 4 5 6 7 8 10 17 12 19 13 14 15 16 11 18 25 20 21 22 23 24 27 28 26 28 29 30 31 32 33 34 35 36 37 38 39

Now we will count the elements, for this we will traverse through the grid again and for each 0 we encounter we will check if the hashSet[i]==i if it is that means that 0 is the starting point of the island chain and we will increment the value by one. Here we use an interesting technique to iterate through the grid and the hashSet at the same time. By the end of this step we will have the count of closed islands in the given grid.

Note: If you check carefully if one 0 is being surrounded by 1s in all sides then it was not considered in the hashSet, but in this step we will count all those type of 0s.

#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

void change(vector<vector<int>> &grid, int x, int y, int c, int r)
{
    if (x < 0 || y < 0 || x > r - 1 || y > c - 1 || grid[x][y] == 1)
        return;

    grid[x][y] = 1;

    change(grid, x + 1, y, c, r);
    change(grid, x, y + 1, c, r);
    change(grid, x - 1, y, c, r);
    change(grid, x, y - 1, c, r);
}

void changeBorder(vector<vector<int>> &grid)
{
    int r = grid.size();
    int c = grid[0].size();

    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            if (i * j == 0 || i == r - 1 || j == c - 1)
            {
                if (grid[i][j] == 0)
                {
                    change(grid, i, j, c, r);
                }
            }
        }
    }
}

int findRoot(vector<int> &hashSet, int val)
{
    while (val != hashSet[val])
    {
        val = hashSet[val];
    }

    return val;
}

void Union(vector<int> &hashSet, int first, int second)
{
    int first_root = findRoot(hashSet, first);

    int second_root = findRoot(hashSet, second);

    if (first_root != second_root)
        hashSet[first_root] = second_root;
}

int closedIslands(vector<vector<int>> &grid)
{

    if (grid.size() == 0)
        return 0;

    int r = grid.size();
    int c = grid[0].size();

    changeBorder(grid);

    vector<pair<int, int>> edges;

    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {

            if (grid[i][j] == 0)
            {
                int id = i * c + j;

                if (j + 1 < c)
                {

                    if (grid[i][j + 1] == 0)
                    {
                        int right = i * c + j + 1;
                        edges.push_back({id, right});
                    }
                }
                if (i + 1 < r)
                {

                    if (grid[i + 1][j] == 0)
                    {
                        int down = (i + 1) * c + j;
                        edges.push_back(make_pair(id, down));
                    }
                }
            }
        }
    }

    vector<int> hashSet(r * c, 0);
    for (int i = 0; i < r * c; i++)
    {
        hashSet[i] = i;
    }

    for (auto edge : edges)
    {
        Union(hashSet, edge.first, edge.second);
    }

    int numComponents = 0;

    for (int i = 0; i < r * c; i++)
    {
        if (grid[i / c][i % c] == 0 && hashSet[i] == i)
            numComponents++;
    }

    return numComponents;
}

int main()
{
    int r, c;
    cin >> r >> c;
    vector<vector<int>> grid(r, vector<int>(c));
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            cin >> grid[i][j];
        }
    }

    cout << closedIslands(grid);
    return 0;
}

The time and space complexity of the above program will be O(r*c)

By now you would have a complete understanding of how to solve this problem.

Number of closed islands [2 solutions]
Share this