[每日一题004]被围绕的区域

本文介绍了如何解决LeetCode中的一个题目,即给定一个由X和O组成的矩阵,找出所有被X包围的O并用X填充。通过递归遍历边界上的O,标记其相邻的O,然后在原地修改矩阵,以达到填充非边界且无连接的O的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每日挑战(C++版)

在这里,我将开始每天练习LeetCode算法题,并将个人解决方案放在这里。


需求介绍

        给你一个 m\times n的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

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

测试例题

  1. 实例1:

                输入:board = [["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"]]

  1. 实例2:

                输入:board = [["X"]]

                输出:[["X"]]


个人分析

        从第二段中描述中可以看出,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。从这句话可以找到解题的思路,就是对边界上的'O'进行递归,将相连的'O'全部保存。在遍历完所有边界上的元素后,没有保存的'O'就被填充为'X'。

        有了上述的解题思路后,就需要进行逻辑的设计。该题有个大前提就是需要在board上进行原地修改,而不是返回一个新的二维数组。

  1. 当二维数组的m或者n小于3时,无需进行判断,因为所有的节点均为边界。不需要对数组进行修改。 
  2. 对边界上的'O'进行递归。需要对二维数组的第一行,最后一行,第一列,最后一列进行遍历判断。从坐标来看
    第一行的坐标从board[0][0], board[0][1], ... board[0][n - 1]。
    最后一行的坐标为board[m-1][0], board[m-1][1], ... board[m-1][n - 1]。
    第一列的坐标从board[0][0], board[1][0], ... board[m-1][0]。
    最后一列的坐标为board[0][n-1], board[0][n-1], ... board[0][n-1]。
    若有相连的,只需要进行坐标变换,递归即可。
  3. 将相连的'O'全部保存。因为要在原数组上进行修改,如果直接在原数组上进行保存,那么无法删选出那些没有相连的'O'。因此需要在采用一个辅助的二维数组用来保存那些'O'是需要保存的。
  4. 最后通过对二维数组进行遍历,加上辅助二维数组的数据,即可完成对不相连'O'的填充。

代码实现

class Solution {
public:
    void search(vector<vector<char>>& board, vector<vector<bool>>& flag, int i, int j, int m, int n)
    {
        // 上
        if(i - 1 >= 0 && board[i - 1][j] == 'O' && !flag[i - 1][j])
        {
            flag[i - 1][j] = true;
            search(board, flag, i - 1, j, m, n);
        }
        // 下
        if(i + 1 < m && board[i + 1][j] == 'O' && !flag[i + 1][j])
        {
            flag[i + 1][j] = true;
            search(board, flag, i + 1, j, m, n);
        }// 左
        if(j - 1 >= 0 && board[i][j - 1] == 'O' && !flag[i][j - 1])
        {
            flag[i][j - 1] = true;
            search(board, flag, i, j - 1, m, n);
        }// 右
        if(j + 1 < n && board[i][j + 1] == 'O' && !flag[i][j + 1])
        {
            flag[i][j + 1] = true;
            search(board, flag, i, j + 1, m, n);
        }
    }

    void solve(vector<vector<char>>& board) {
        int m = board.size();
        int n = board[0].size();
        vector<vector<bool>> flag(m, vector<bool>(n, false));
        if(m > 2 && n > 2)
        {
            // 第一行和最后一行
            for(int i = 0; i < n; i++)
            {
                if(board[0][i] == 'O')
                {
                    flag[0][i] = true;
                    search(board, flag, 0, i, m, n);
                }
                if(board[m - 1][i] == 'O')
                {
                    flag[m-1][i] = true;
                    search(board, flag, m - 1, i, m, n);
                }
            }
            // 第一列和最后一列
            for(int j = 0; j < m; j++)
            {
                if(board[j][0] == 'O')
                {
                    flag[j][0] = true;
                    search(board, flag, j, 0, m, n);
                }
                if(board[j][n-1] == 'O')
                {
                    flag[j][n-1] = true;
                    search(board, flag, j, n-1, m, n);
                }
            }
            for(int i = 0; i < m; i++)
            {
                for(int j = 0; j < n; j++)
                {
                    if(!flag[i][j] && board[i][j] == 'O')
                    {
                        board[i][j] = 'X';
                    }
                }
            }
        }
    }
};

总结

上诉代码在时间上超过了71.66%的用户,内存上超过了11.54%的用户。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值