【算法积累】被围绕的区域

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'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。


解法 深度优先搜索(DFS)
题目解释中提到,任何边界上的'O'都不会被填充为'X'。不难发现,所有的不被包围的'O'都直接或间接与边界上的'O'相连。对于每一个边界上的'O',以其为起点,利用深度优先搜索的方法,将所有与其直接或间接相连的字母'O'标记为特殊符号'#'。搜索结束后,遍历给定的二维矩阵,如果字母为'O',则将其改写为'X';如果字母被标记为'#',则将其还原为'O'
语言:C

void dfs(char** board, int i, int j, int row, int col) {
    if (i >= row || i < 0 || j >= col || j < 0 || board[i][j] != 'O') {
        return;
    }
    board[i][j] = '#';
    dfs(board, i - 1, j, row, col);
    dfs(board, i + 1, j, row, col);
    dfs(board, i, j - 1, row, col);
    dfs(board, i, j + 1, row, col);
}

void solve(char** board, int boardSize, int* boardColSize) {
    if (boardSize == 0) {
        return;
    }
    int row = boardSize;
    int col = boardColSize[0];
    // 沿行遍历边界
    for (int i = 0; i < col; i++) {
        if (board[0][i] == 'O') {
            dfs(board, 0, i, row, col);
        }
        if (board[row - 1][i] == 'O') {
            dfs(board, row - 1, i, row, col);
        }
    }
    // 沿列遍历边界
    for (int i = 0; i < row; i++) {
        if (board[i][0] == 'O') {
            dfs(board, i, 0, row, col);
        }
        if (board[i][col - 1] == 'O') {
            dfs(board, i, col - 1, row, col);
        }
    }
    // 改写矩阵
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            if (board[i][j] == 'O') {
                board[i][j] = 'X';
            } else if (board[i][j] == '#') {
                board[i][j] = 'O';
            }
        }
    }
}

时间复杂度: O ( n × m ) O(n\times m) O(n×m),其中 n n n m m m分别为二维矩阵的行数和列数。
空间复杂度: O ( n × m ) O(n\times m) O(n×m),其中 n n n m m m分别为二维矩阵的行数和列数,主要为深度优先搜索的栈的开销。

这道题还可以使用广度优先搜索(BFS)或者并查集来解决,不过这周的事情有一些多,先写一个较为简单的DFS的解法,后面有时间了再把BFS和并查集的解法补上。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值