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

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

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

示例:

X X X X
X O O X
X X O X
X O X X

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

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替换为标记为*

X X X X
X O O X
X X O X
X * X X

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

X X X X
X O O X
X X O X
X O O X

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

X X X X
X * * X
X X * X
X * * X

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

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的写法。

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:岛屿的个数(最详细的解法!!!)问题中的迭代版本写法类似。

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

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

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值