Leetcode 130:被围绕的区域(最详细的解法!!!)

给定一个二维的矩阵,包含 'X''O'字母 O)。

找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O''X' 填充。

示例:

1
2
3
4
X X X X
X O O X
X X O X
X O X X

运行你的函数后,矩阵变为:

1
2
3
4
X X X X
X X X X
X X X X
X O X X

解释:

被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

解题思路

这个问题,和之前的 Leetcode 79:单词搜索(最详细的解法!!!)Leetcode 200:岛屿的个数(最详细的解法!!!)很类似。这个问题一个很简单的处理思路就是将外围的O元素单独考虑。基于这个思路,我们将外围的O替换为标记为*

1
2
3
4
X X X X
X O O X
X X O X
X * X X

然后我们就只要将图中的O替换成X,将*替换成O即可。这里有这样一种情况

1
2
3
4
X X X X
X O O X
X X O X
X O O X

这里的O全部就外围元素。替换为*,就变成了

1
2
3
4
X X X X
X * * X
X X * X
X * * X

所以我们现在的问题就变成了:在这个图的边界位置出发找连通的O。这就和之前的问题联系在一起了。

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
class Solution:
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not board:
return None

m, n = len(board), len(board[0])
d = [(-1, 0), (0, 1), (1, 0), (0, -1)]

def _solve(i, j):
if 0 <= i < m and 0 <= j < n and board[i][j] == 'O':
board[i][j] = '*'
for k in range(4):
_solve(i + d[k][0], j + d[k][1])

for i in range(m):
_solve(i, 0)
_solve(i, n - 1)

for i in range(n):
_solve(0, i)
_solve(m - 1, i)

for i in range(m):
for j in range(n):
if board[i][j] == 'O':
board[i][j] = 'X'
elif board[i][j] == '*':
board[i][j] = 'O'

我们有一个更pythonic的写法。

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
class Solution:
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not board:
return None

m, n = len(board), len(board[0])

def _solve(i, j):
if 0 <= i < m and 0 <= j < n and board[i][j] == 'O':
board[i][j] = '*'
list(map(_solve, (i+1, i-1, i, i), (j, j, j+1, j-1)))

for i in range(m):
list(map(_solve, (i, i), (0, n - 1)))

for i in range(n):
list(map(_solve, (0, m - 1), (i, i)))

for i in range(m):
for j in range(n):
if board[i][j] == 'O':
board[i][j] = 'X'
elif board[i][j] == '*':
board[i][j] = 'O'

要注意的是python3中,map函数返回的是一个iterator,所以我们要通过list将包在外面,去自动推导它。

同样的,对于递归解决的问题,我们都应该思考一下怎么通过迭代去解决。写法和Leetcode 200:岛屿的个数(最详细的解法!!!)问题中的迭代版本写法类似。

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
40
41
42
class Solution:
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not board:
return None

m, n = len(board), len(board[0])

def _solve(i, j):
if board[i][j] != 'O':
return

stack = list()
stack.append((i, j))
while stack:
x, y = stack.pop()
if board[x][y] != 'O':
continue

board[x][y] = '*'
directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]
for d in directions:
nr = x + d[0]
nc = y + d[1]
if 0 <= nr < m and 0 <= nc < n:
stack.append((nr, nc))

for i in range(m):
list(map(_solve, (i, i), (0, n - 1)))

for i in range(n):
list(map(_solve, (0, m - 1), (i, i)))

for i in range(m):
for j in range(n):
if board[i][j] == 'O':
board[i][j] = 'X'
elif board[i][j] == '*':
board[i][j] = 'O'

我们将self._solve写成一个迭代版本即可。

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!