将矩阵中所有被X包围的O转换为X Surrounded Regions

本文介绍了一种解决二维棋盘中被X包围的O型区域的问题,通过三种不同的算法实现:深度优先搜索(DFS)优化版、更易理解的DFS优化版及广度优先搜索(BFS)。每种方法都详细展示了如何将边缘不受X包围的O标记并保留,最终将所有未标记的O转换为X。

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

问题:

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.

A region is captured by flipping all 'O's into 'X's in that surrounded region.

For example,

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

After running your function, the board should be:

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

解决:

① 将被X包围的O都转化为X,边缘的O不算被包围,所以先对边界上的'O'遍历之后暂存为'*',非'*'的'O'即被'X'包围了。使用DFS。

class Solution { //栈溢出异常,因为方法调用太多
    public void solve(char[][] board) {
        if(board == null || board.length == 0) return;
        int m = board.length;
        int n = board[0].length;
        for (int i = 0;i < m ;i ++ ) {
            if(board[i][0] == 'O'){
                dfs(board,i,0);//将边缘的O替换为X
            }
            if (board[i][n - 1] == 'O') {
                dfs(board,i,n - 1);
            }
        }
        for (int j = 0;j < n ;j ++ ) {
            if (dfs[0][j] == 'O') {
                dfs(board,0,j);
            }
            if(board[m - 1][j] == 'O'){
                dfs(board,m - 1,j);
            }
        }
        for (int i = 0;i < m ;i ++ ) {
            for (int j = 0;j < n ;j ++ ) {
                if(board[i][j] == 'O'){
                    board[i][j] = 'X';
                }else if(board[i][j] == '*'){
                    board[i][j] = 'O';
                }
            }
        }
    }
    public void dfs(char[][] board,int i,int j){
        if(i < 0 || i >= board.length || j < 0 || j >= board[0].length){
            return;
        }
        if(board[i][j] != 'O') return;
        board[i][j] = '*';
        dfs(board,i - 1,j);
        dfs(board,i + 1,j);
        dfs(board,i,j - 1);
        dfs(board,i,j + 1);
    }
}

② 在discuss中看到的,对上面的dfs方法进行优化。

class Solution { //4ms
    public void solve(char[][] board){
        if (board == null || board.length == 0 || board[0].length == 0) {
            return;
        }
        int m = board.length;
        int n = board[0].length;
        for (int i = 0;i < m ;i ++ ) {
            if(board[i][0] == 'O'){//替换边界上的‘O’
                dfs(board,i,0);
            }
        }
        if (n - 1 > 0) {//判断矩阵是否大于1列!若不是,就不需要额外的判断了,因为上面的判断已经实现了
            for (int i = 0;i < m ;i ++ ) {
                if (board[i][n - 1] == 'O') {
                    dfs(board,i,n - 1);
                }
            }
        }
        for (int i = 1;i < n - 1 ;i ++ ) {//i从1开始到n - 1结束,是为了跳过已经判断了的点
            if (board[0][i] == 'O') {
                dfs(board,0,i);
            }
        }
        if (n - 1 > 0) {//添加额外的判断,而且与上面的一样!!!,这是因为如果只有1列的话就不需要再判断了。
            for (int i = 1;i < n - 1 ;i ++ ) {
                if (board[m - 1][i] == 'O') {
                    dfs(board,m - 1,i);
                }
            }
        }
        for (int i = 1;i < n - 1 ;i ++ ) { //此处判断列是为了什么?经测试,可以不添加该部分,只是运行时间多了2ms
            dfs(board,0,i);
            if (m > 1) {
                dfs(board,m - 1,i);
            }
        }

        for (char[] rows : board ) { //修改被包围的'O'
            for (int i = 0;i < rows.length ;i ++ ) {
                if (rows[i] == 'O') {
                    rows[i] = 'X';
                }
            }
        }
        for (char[] rows : board) {//还原边界上的‘O’
            for (int i = 0;i < rows.length ;i ++ ) {
                if (rows[i] == '*') {
                    rows[i] = 'O';
                }
            }
        }
    }
    public void dfs(char[][] board,int i,int j){
        if (board[i][j] != 'O') {
            return;
        }
        board[i][j] = '*';
        if (i < board.length - 2) { //i行下面至少还有1行,由于该行没有被包围,所以继续往下判断
            dfs(board,i + 1,j);
        }
        if (i > 1) { //向上判断
            dfs(board,i - 1,j);
        }
        if (j > 1) { //向左判断
            dfs(board,i,j - 1);
        }
        if (j < board[0].length - 2) { //向右判断
            dfs(board,i,j + 1);
        }
    }//总之,就是将边界处的O改写之后,继续向内层判断是否有没被包含的O
}

③ 在discuss中看到,更好理解一点的优化方法。

class Solution { //5ms
    public void solve(char[][] board) {
        int m = board.length;
        if(m == 0) return;
        int n = board[0].length;
        for (int i = 0;i < m ;i ++ ) {
            dfs(board,i,0,m,n);//标记左边界
            if (n > 1) {
                dfs(board,i,n - 1,m,n);//标记右边界
            }
        }

        for (int j = 1;j + 1 < n ;j ++ ) {
            dfs(board,0,j,m,n);//标记上边界  
            if (m > 1) {
                dfs(board,m - 1,j,m,n);//标记下边界
            }
        }
        for (int i = 0;i < m ;i ++ ) {
            for (int j = 0;j < n ;j ++ ) {
                if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
                if (board[i][j] == '*') {
                    board[i][j] = 'O';
                }
            }
        }
    }
    public void dfs(char[][] board,int i,int j,int m,int n){
        if (board[i][j] == 'O') {
            board[i][j] = '*';
            if (i > 1) {
                dfs(board,i - 1,j,m,n);
            }
            if (j > 1) {
                dfs(board,i,j - 1,m,n);
            }
            if (i + 1 < m) {
                dfs(board,i + 1,j,m,n);
            }
            if (j + 1 < n) {
                dfs(board,i, j + 1,m,n);
            }
        }
    }
}

③ BFS遍历

class Solution { //10ms
    public void solve(char[][] board){
        if(board == null || board.length == 0 || board[0].length == 0) return;
        int m = board.length;
        int n = board[0].length;
        for (int j = 0;j < n ;j ++ ) {//处理第一行与最后一行
            if(board[0][j] == 'O'){
                bfs(board,0,j);
            }
            if(board[m - 1][j] == 'O'){
                bfs(board,m - 1,j);
            }
        }
        for (int i = 0;i < m ;i ++ ) {//处理第一列与最后一列
            if(board[i][0] == 'O'){
                bfs(board,i,0);
            }
            if (board[i][n - 1] == 'O') {
                bfs(board,i,n - 1);
            }
        }
        for (int i = 0;i < m ;i ++ ) {
            for (int j = 0;j < n ;j ++ ) {
                if(board[i][j] == 'O'){
                    board[i][j] = 'X';
                }
                if (board[i][j] == '*') {
                    board[i][j] = 'O';
                }
            }
        }
    }
    public void bfs(char[][] board,int i,int j){
        int m = board.length;
        int n = board[0].length;
        int index = i * n + j; //计算当前点的个数
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(index);
        board[i][j] = '*';
        while(! queue.isEmpty()){
            int top = queue.poll();
            int x = top / n; 
            int y = top % n;

            if(x - 1 >= 0 && board[x - 1][y] == 'O'){
                board[x - 1][y] = '*';
                queue.offer((x - 1) * n + y);
            }
            if (x + 1 < m && board[x + 1][y] == 'O') {
                board[x + 1][y] = '*';
                queue.offer((x + 1) * n + y);
            }
            if (y - 1 >= 0 && board[x][y - 1] == 'O') {
                board[x][y - 1] = '*';
                queue.offer(x * n + y - 1);
            }
            if (y + 1 < n && board[x][y + 1] == 'O') {
                board[x][y + 1] = '*';
                queue.offer(x * n + y + 1);
            }
        }
    }
}

转载于:https://my.oschina.net/liyurong/blog/1544484

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值