You are given an m x n matrix board containing letters 'X' and 'O', capture regions that are surrounded:
'O' cell.'X' cells if you can connect the region with 'X' cells and none of the region cells are on the edge of the board.To capture a surrounded region, replace all 'O's with 'X's in-place within the original board. You do not need to return anything.
Example 1:
Input: board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]
Output: [["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
Explanation:
In the above diagram, the bottom region is not captured because it is on the edge of the board and cannot be surrounded.
Example 2:
Input: board = [["X"]]
Output: [["X"]]
Constraints:
m == board.lengthn == board[i].length1 <= m, n <= 200board[i][j] is 'X' or 'O'.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We're trying to capture regions of 'O's on a grid that are completely surrounded by 'X's. The brute force way is to examine each 'O' on the grid individually and meticulously check if it's surrounded by 'X's.
Here's how the algorithm would work step-by-step:
def solve_surrounded_regions(board):
if not board or not board[0]:
return
number_of_rows = len(board)
number_of_columns = len(board[0])
def explore_and_flip(row_index, column_index, visited, initial_row, initial_column):
if row_index < 0 or row_index >= number_of_rows or \
column_index < 0 or column_index >= number_of_columns or \
(row_index, column_index) in visited or \
board[row_index][column_index] == 'X':
return True
visited.add((row_index, column_index))
if row_index == 0 or row_index == number_of_rows - 1 or \
column_index == 0 or column_index == number_of_columns - 1:
return False
up = explore_and_flip(row_index - 1, column_index, visited, initial_row, initial_column)
down = explore_and_flip(row_index + 1, column_index, visited, initial_row, initial_column)
left = explore_and_flip(row_index, column_index - 1, visited, initial_row, initial_column)
right = explore_and_flip(row_index, column_index + 1, visited, initial_row, initial_column)
return up and down and left and right
def flip_region(row_index, column_index, flipped):
if row_index < 0 or row_index >= number_of_rows or \
column_index < 0 or column_index >= number_of_columns or \
(row_index, column_index) in flipped or \
board[row_index][column_index] == 'X':
return
flipped.add((row_index, column_index))
board[row_index] = board[row_index][:column_index] + 'X' + board[row_index][column_index+1:]
flip_region(row_index - 1, column_index, flipped)
flip_region(row_index + 1, column_index, flipped)
flip_region(row_index, column_index - 1, flipped)
flip_region(row_index, column_index + 1, flipped)
for row_index in range(number_of_rows):
for column_index in range(number_of_columns):
if board[row_index][column_index] == 'O':
visited_cells = set()
#Checking if region is surrounded
is_surrounded = explore_and_flip(row_index, column_index, visited_cells, row_index, column_index)
if is_surrounded:
flipped_cells = set()
#Flip the region
flip_region(row_index, column_index, flipped_cells)The goal is to flip 'O's to 'X's in a grid, but only the 'O's that are completely surrounded by 'X's. The clever idea is to start from the edges of the grid and mark the 'O's connected to the edges as safe, then flip the rest.
Here's how the algorithm would work step-by-step:
def solve_surrounded_regions(board):
if not board:
return
number_of_rows = len(board)
number_of_columns = len(board[0])
def depth_first_search(row, column):
if row < 0 or row >= number_of_rows or \
column < 0 or column >= number_of_columns or \
board[row][column] != 'O':
return
board[row][column] = 'T'
depth_first_search(row + 1, column)
depth_first_search(row - 1, column)
depth_first_search(row, column + 1)
depth_first_search(row, column - 1)
# Iterate through the edges and mark connected 'O's as 'T'
for row_index in range(number_of_rows):
if board[row_index][0] == 'O':
depth_first_search(row_index, 0)
if board[row_index][number_of_columns - 1] == 'O':
depth_first_search(row_index, number_of_columns - 1)
for column_index in range(number_of_columns):
if board[0][column_index] == 'O':
depth_first_search(0, column_index)
if board[number_of_rows - 1][column_index] == 'O':
depth_first_search(number_of_rows - 1, column_index)
# Capture all 'O's that were not connected to the edge
for row_index in range(number_of_rows):
for column_index in range(number_of_columns):
if board[row_index][column_index] == 'O':
board[row_index][column_index] = 'X'
# Revert temporary 'T's back to 'O's
if board[row_index][column_index] == 'T':
board[row_index][column_index] = 'O'
# After processing, the board is modified in-place,
# no explicit return is needed.
return board| Case | How to Handle |
|---|---|
| Null or empty board | Return immediately if the board is null or has zero rows or columns. |
| Board with only one row or one column | If the board has only one row or column, 'O's on the border are already connected and should not be flipped, therefore, no action should be taken. |
| Board filled entirely with 'X's | No 'O's exist so no changes are required and the board remains as is. |
| Board filled entirely with 'O's | All 'O's except those on the boundary should be flipped to 'X'. |
| Board with 'O's clustered in the middle, completely surrounded by 'X's | These 'O's should be flipped to 'X's. |
| Board with 'O's connected to the boundary | These 'O's and any 'O's they connect to should be treated as safe and remain 'O's. |
| Very large board (memory constraints) | Ensure that the algorithm uses in-place modification to avoid excessive memory usage and prevent potential out-of-memory errors. |
| Deep recursion with many connected 'O's to the boundary (stack overflow) | Use an iterative approach (e.g., using a queue) instead of recursion to explore connected components and avoid potential stack overflow errors on very large boards. |