Surrounded regions

Difficulty: Hard

Asked in: Google

Understanding The Problem

Problem Description

Given a 2-D matrix board where every element is either O or ‘X, write a program to replace O with X if surrounded by X’.

Problem Note

  • An O or a set of O is considered to be by surrounded by X if there are X at locations just below, just above just left and just right of it.
  • Surrounded regions shouldn’t be on the border, which means that any 'O' on the border of the board are not flipped to 'X'.
  • Any 'O' that is not on the border and it is not connected to an 'O' on the border will be flipped to 'X'.
  • Two cells are connected if they are adjacent cells connected horizontally or vertically.

Example 1

Input: board[][] = [ 
                 ['X', 'O', 'X', 'X', 'X', 'X'],
                 ['X', 'O', 'X', 'X', 'O', 'X'],
                 ['X', 'X', 'X', 'O', 'O', 'X'],
                 ['O', 'X', 'X', 'X', 'X', 'X'],
                 ['X', 'X', 'X', 'O', 'X', 'O'],
                 ['O', 'O', 'X', 'O', 'O', 'O'],
               ]
Output: board[][] = [ 
                  ['X', 'O', 'X', 'X', 'X', 'X'],
                  ['X', 'O', 'X', 'X', 'X', 'X'],
                  ['X', 'X', 'X', 'X', 'X', 'X'],
                  ['O', 'X', 'X', 'X', 'X', 'X'],
                  ['X', 'X', 'X', 'O', 'X', 'O'],
                  ['O', 'O', 'X', 'O', 'O', 'O'],
                ]

Example 2

Input: board[][] = [ 
                 ['X', 'X', 'X', 'X']
                 ['X', 'O', 'X', 'X']
                 ['X', 'O', 'O', 'X']
                 ['X', 'O', 'X', 'X']
                 ['X', 'X', 'O', 'O']
               ]
Output: board[][] = [ 
                  ['X', 'X', 'X', 'X']
                  ['X', 'X', 'X', 'X']
                  ['X', 'X', 'X', 'X']
                  ['X', 'X', 'X', 'X']
                  ['X', 'X', 'O', 'O']
                ]

Solutions

This problem can be solved by the famous Flood Fill Algorithm. The main difference here is that a 'O'is not replaced by 'X' if it lies in a region that ends on a boundary.

Flood fill algorithm can be simply explained as a graph traversal problem, representing the given area as a matrix and considering every cell of that matrix as a vertex that is connected to points above it, below it, to the right of it, and to the left of it. In general, any cell [x,y] connected with [x-1][y], [x+1][y], [x][y-1], [x][y+1] cells.

For this problem, the flood fill algorithm can be explained as a recursive function that will convert all the mark A with mark B of the input board matrix.

void floodFillUtil(char[][] board, int x, int y, char markA, char markB, int dimsX, int dimsY) 
{ 
    if (x < 0 or x >= dimsX or y < 0 or y >= dimsY) 
        return
    if (board[x][y] != markA)
        return
    // Replace the mark
    board[x][y] = markB
    // Recur for the four directions
    floodFillUtil(board, x+1, y, markA, markB, dimsX, dimsY)
    floodFillUtil(board, x-1, y, markA, markB, dimsX, dimsY)
    floodFillUtil(board, x, y+1, markA, markB, dimsX, dimsY)
    floodFillUtil(board, x, y-1, markA, markB, dimsX, dimsY)
}

So, The idea is very simple, we will convert all the 'O' to '$' . Now we will search for all the ‘$’ at the boundary of the matrix and for each such ‘$’ we will apply the flood fill algorithm to convert them to ‘O’ . In this way, we will be left with all the ‘$’ which will be surrounded by only ‘X’ .

You can try the problem here.

Example 1 can be visualized as

['X', 'O', 'X', 'X', 'X', 'X']
['X', 'O', 'X', 'X', 'O', 'X']
['X', 'X', 'X', 'O', 'O', 'X']
['O', 'X', 'X', 'X', 'X', 'X']
['X', 'X', 'X', 'O', 'X', 'O']
['O', 'O', 'X', 'O', 'O', 'O']
convert all O to $
['X', '$', 'X', 'X', 'X', 'X']
['X', '$', 'X', 'X', '$', 'X']
['X', 'X', 'X', '$', '$', 'X']
['$', 'X', 'X', 'X', 'X', 'X']
['X', 'X', 'X', '$', 'X', '$']
['$', '$', 'X', '$', '$', '$']
Choose boundry $ and flood fill them with O
['X', 'O', 'X', 'X', 'X', 'X']
['X', 'O', 'X', 'X', '$', 'X']
['X', 'X', 'X', '$', '$', 'X']
['O', 'X', 'X', 'X', 'X', 'X']
['X', 'X', 'X', 'O', 'X', 'O']
['O', 'O', 'X', 'O', 'O', 'O']
Replace all the $ with X
['X', 'O', 'X', 'X', 'X', 'X']
['X', 'O', 'X', 'X', 'X', 'X']
['X', 'X', 'X', '$', 'X', 'X']
['O', 'X', 'X', 'X', 'X', 'X']
['X', 'X', 'X', 'O', 'X', 'O']
['O', 'O', 'X', 'O', 'O', 'O']

Solution steps

  • Create a flood fill function, which recursively marks each node with the input symbol in DFS fashion until it touches the boundary where the boundary will be the end of the matrix or boundary of different symbols.
  • Convert each ‘O’ to ‘$’
  • Apply flood fill for all the boundary ‘$’ to convert into ‘O’
  • Now replace all the left ‘$’ into ‘X’

Pseudo Code

void floodFillUtil(char[][] board, int x, int y, char markA, char markB) 
{ 
    if (x < 0 or x >= board[0].size() or y < 0 or y >= board.size) 
        return
    if (board[x][y] != markA)
        return
    // Replace the mark
    board[x][y] = markB
    // Recur for the four directions
    floodFillUtil(board, x+1, y, markA, markB)
    floodFillUtil(board, x-1, y, markA, markB)
    floodFillUtil(board, x, y+1, markA, markB)
    floodFillUtil(board, x, y-1, markA, markB)
}
void surroundedRegions(char[][] board, int dimsX, dimsY) 
{
    for (int i=0 to i < dimsX) 
        for (int j=0 to j < dimsY) 
            if (board[i][j] is 'O')
                board[i][j] = '$'
    for (int i=0 to i < dimsX)  // Left boundry
        if (board[i][0] is '$') 
            floodFillUtil(board, i, 0, '$', 'O')
    for (int i=0 to i < dimsX)  //  Right boundry
        if (board[i][dimsY - 1] is '$')
            floodFillUtil(board, i, dimsY - 1, '$', 'O')
    for (int i=0 to i<dimsY)   // Top boundry
        if (board[0][i] is '$') 
            floodFillUtil(board, 0, i, '$', 'O')
    for (int i=0; i<dimsY; i++)  // Bottom boundry
        if (board[dimsX - 1][i] is '$') 
            floodFillUtil(board, dimsX - 1, i, '$', 'O')
    for (int i=0 to i < dimsX)
        for (int j=0 to j < dimsY) 
            if (board[i][j] is '$') 
                board[i][j] = 'X'
}

Complexity Analysis

Time Complexity: O(n²)

Space Complexity: O(n²)

where n² is the size of the board matrix.

Critical Ideas To Think

  • What does the flood fill algorithm do?
  • How come we assumed the matrix as a graph and considered adjacent nodes as connected nodes?
  • Why did we first converted all the 'O' into '$'?
  • Floodfill acts like a DFS algorithm in the above pseudo-code. Do you think, converting it into a BFS algorithm will affect the solution?

Suggested Problems To Solve

  • Number of islands
  • Flood fill an image
  • Determine the perimeter of the island if 1's in the matrix represent an island and 0's represent water.
  • Implement a fill function for the paint's color fill tool.

Please comment down below if you have a better insight in the above approach.

Happy Coding, Enjoy Algorithms!