LeetCode 130

来源:8-7 floodfill算法,一类经典问题 Number of Islands-

慕妹2978617

2023-08-11

  1. 被围绕的区域

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

输入: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”]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的 ‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

package com.ggxiaozhi.leetcodenew.class8;

import java.util.Arrays;

/**
 * 130. 被围绕的区域
 * 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
 * <p>
 * 思路
 * 1  floodFill 找到0 然后记录0的合法区域
 * 2  找到0但不合法直接返回 不记录
 */
public class Solution130 {
     static int[][] way = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
     static int m, n;

    public static void solve(char[][] board) {
        m = board.length;
        n = board[0].length;
        boolean[][] used = new boolean[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!used[i][j] && board[i][j] == '0') {
                    searchZero(board, i, j, used);
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (used[i][j]) {
                    board[i][j] = 'X';
                }
            }
        }

    }

    //找到0 后就要判断 4个方向上有没有不合法的 存在 则当前这个0是无效的 不加入used
    private static void searchZero(char[][] board, int x, int y, boolean[][] used) {
        used[x][y] = true;
        for (int[] ints : way) {
            int nextX = x + ints[0];
            int nextY = y + ints[1];

            if (isValid(nextX, nextY)) {
                if (!used[nextX][nextY] && board[nextX][nextY] == '0')
                    searchZero(board, nextX, nextY, used);
            } else {
                used[x][y] = false;
                break;
            }
        }
    }


    public static boolean isValid(int x, int y) {
        return x >= 0 && y >= 0 && x < m && y < n;
    }

    public static void main(String[] args) {
        char[][] chars = {
                {'X', 'X', 'X', 'X'},
                {'X', '0', '0', 'X'},
                {'X', 'X', '0', 'X'},
                {'X', '0', 'X', 'X'}
        };
        solve(chars);
        System.out.println(Arrays.deepToString(chars));
    }
}

我这个代码 用官方上述例子跑出来在本地是对的,放到leetcode上就是错的,老师可以帮看下原因吗?

写回答

2回答

慕妹2978617

提问者

2023-08-11

本来从搜索O的角度出发,写出

searchZero

不对后,想到排除边缘干扰因此想出

searchEdge


后来看别人的题解,突然恍然大悟,我都写出searchEdge()了,
那isEdgeUsed,不就是标记着哪写O是不用修改的,那剩下的不就全都是'X'了,完全可以不用这个方法。

只需要去掉searchZero()方法 
将下面的代码
for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        if (!isEdgeUsed[i][j]) {
            board[i][j] = 'X';
        }
    }
}
改成
for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        if (!isEdgeUsed[i][j]) {
            board[i][j] = 'X';
        }
    }
}
这个遍历也可以完全不用了

public class Solution {
    static int[][] way = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    static int m, n;

    static boolean[][] isEdgeUsed;
    public static void solve(char[][] board) {
        m = board.length;
        n = board[0].length;
        //合法是否被用过
        isEdgeUsed = new boolean[m][n];
        //先找到所有边缘 和与边缘连接的O 并记录在 isEdgeUsed中
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!isEdgeUsed[i][j] && board[i][j] == 'O' && isEdge(i, j)) {
                    searchEdge(board, i, j, isEdgeUsed);
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!isEdgeUsed[i][j]) {
                    board[i][j] = 'X';
                }
            }
        }

    }

    //找到0 后就要判断 4个方向上有没有不合法的 存在 则当前这个0是无效的 不加入used
    private static void searchEdge(char[][] board, int x, int y, boolean[][] isEdgeUsed) {
        isEdgeUsed[x][y] = true;
        for (int[] ints : way) {
            int nextX = x + ints[0];
            int nextY = y + ints[1];

            if (isValid(nextX, nextY)) {
                if (!isEdgeUsed[nextX][nextY] && board[nextX][nextY] == 'O')
                    searchEdge(board, nextX, nextY, isEdgeUsed);
            }
        }
    }

    public static boolean isValid(int x, int y) {
        return x >= 0 && y >= 0 && x < m && y < n;
    }

    public static boolean isEdge(int x, int y) {
        return x == 0 || y == 0 || x == m - 1 || y == n - 1;
    }
}

我真是太笨了。不过时间效率还是没到50%(43%)。老师觉得能这个代码还能优化嘛!

0
1
liuyubobobo
大赞自己解决问题的过程! 从正向思维的角度,这个代码在我看来已经可以了。你可以思考一下,是否可以“逆向思考”?即先从边缘出发,标记和边缘连接的O,之后所有的没有标记过的 O,就都是需要修改的了:) 继续加油!:)
2023-08-14
共1条回复

慕妹2978617

提问者

2023-08-11

找到原因了,题目是O,我看成了0了。

但是还是有问题,属于是我理解的问题,我以为和边缘连接的O是合法的,需要改成X,但实际不用。我服用下代码想到个方案,但就是感觉有些重复,不知道怎么拆分简化。但是对我来说却比较好理解。老师有时间的话,可以针对我的代码给个优化建议

//        char[][] chars = {
//                {'O', 'O', 'O'},
//                {'O', 'O', 'O'},
//                {'O', 'O', 'O'},
//        };
我以为 中间的O需要改成X ,所以上面的代码不对 改成了下面的就对了
package com.ggxiaozhi.leetcodenew.class8;

import java.util.Arrays;

/**
 * 130. 被围绕的区域
 * 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
 * <p>
 * 思路
 * 1  floodFill 找到0 然后记录0的合法区域
 * 2  找到0但不合法直接返回 不记录
 */
public class Solution130 {
    static int[][] way = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    static int m, n;
    static boolean[][] used;

    static boolean[][] isEdgeUsed;

    public static void solve(char[][] board) {
        m = board.length;
        n = board[0].length;
        //合法是否被用过
        used = new boolean[m][n];

        isEdgeUsed = new boolean[m][n];

        //先找到所有边缘 和与边缘连接的O 并记录在 isEdgeUsed中
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (isEdge(i, j)&&!isEdgeUsed[i][j] && board[i][j] == 'O'  ) {
                    searchEdge(board, i, j, isEdgeUsed);
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!isEdge(i, j) && !used[i][j] && board[i][j] == 'O' && !isEdgeUsed[i][i]) {
                    searchZero(board, i, j, used);
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (used[i][j]) {
                    board[i][j] = 'X';
                }
            }
        }

    }

    //找到0 后就要判断 4个方向上有没有不合法的 存在 则当前这个0是无效的 不加入used
    private static void searchEdge(char[][] board, int x, int y, boolean[][] isEdgeUsed) {
        isEdgeUsed[x][y] = true;
        for (int[] ints : way) {
            int nextX = x + ints[0];
            int nextY = y + ints[1];

            if (isValid(nextX, nextY)) {
                if (!isEdgeUsed[nextX][nextY] && board[nextX][nextY] == 'O')
                    searchEdge(board, nextX, nextY, isEdgeUsed);
            }
        }
    }

    private static void searchZero(char[][] board, int x, int y, boolean[][] used) {
        used[x][y] = true;
        for (int[] ints : way) {
            int nextX = x + ints[0];
            int nextY = y + ints[1];

            if (isValid(nextX, nextY) && !isEdgeUsed[nextX][nextY]) {
                if (!used[nextX][nextY] && board[nextX][nextY] == 'O')
                    searchZero(board, nextX, nextY, used);
            } else {
                used[x][y] = false;
                break;
            }
        }
    }

    public static boolean isValid(int x, int y) {
        return x >= 0 && y >= 0 && x < m && y < n;
    }

    public static boolean isEdge(int x, int y) {
        return x == 0 || y == 0 || x == m - 1 || y == n - 1;
    }

    public static void main(String[] args) {
        char[][] chars = {
                {'X', 'X', 'X', 'X'},
                {'X', 'O', 'O', 'X'},
                {'X', 'X', 'O', 'X'},
                {'X', 'O', 'X', 'X'}

        };

//        char[][] chars = {
//                {'O', 'O', 'O'},
//                {'O', 'O', 'O'},
//                {'O', 'O', 'O'},
//        };
        solve(chars);
        System.out.println(Arrays.deepToString(chars));
    }
}


0
1
慕妹2978617
我想到一种优化
2023-08-11
共1条回复

玩转算法面试-- Leetcode真题分门别类讲解

课程配套大量BAT面试真题,高频算法题解析,强化训练

7408 学习 · 1150 问题

查看课程