[Leetcode学习-java]Surrounded Regions(翻转围绕区域)

问题:

难度:medium

说明:

题目会输入一个二维char[][] charArr,如果发现有X包围O地区,就将O的上下左右联通块(四个斜角的不属于联通块)全部变成X,如果O在边界,就视为没有包围,有点像翻转棋。

问题链接:https://leetcode.com/problems/surrounded-regions/

输入案例:

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:
// 中间几个O被包围就改成X,然而边界的O视为没有被包围,所以不用修改
X X X X
X X X X
X X X X
X O X X

我的代码:

用bfs + visited处理,这个做法跟岛屿扫描很相似,所以可以根据那个处理处来,相对来说算法效率略慢,7ms,也没有特别短和容易的代码,大多业务处理所以就没看其他代码了。

public class SurroundedRegions {

    public static void main(String[] args) {
        Solution solution = new SurroundedRegions().new Solution();

        char[][] board01 = {{'X'}};

        // 边界元素不进行遍历,并且触边情况要跳出联通块计算
        char[][] board02 = {
                {'X','O','X','X'},
                {'O','X','O','X'},
                {'X','O','X','O'},
                {'O','X','O','X'}};

        // visited已经是1的就不要遍历
        char[][] board03 = {
                {'O','X','X','O','X'},
                {'X','O','O','X','O'},
                {'X','O','X','O','X'},
                {'O','X','O','O','O'},
                {'X','X','O','X','O'}};

        // 7,6那个地方,因为判断里面一旦触边就跳出,导致四周被遍历为1,只有他自己是0就出错了
        // 改成flag判断是否触边,然后遍历所有联通块即可
        char[][] board04 = {
                {'O','X','O','O','O','O','O','O','O'},
                {'O','O','O','X','O','O','O','O','X'},
                {'O','X','O','X','O','O','O','O','X'},
                {'O','O','O','O','X','O','O','O','O'},
                {'X','O','O','O','O','O','O','O','X'},
                {'X','X','O','O','X','O','X','O','X'},
                {'O','O','O','X','O','O','O','O','O'},
                {'O','O','O','X','O','O','O','O','O'},
                {'O','O','O','O','O','X','X','O','O'}};

        // 末尾判断出错
        solution.solve(board01);
        solution.solve(board02);
        solution.solve(board03);
        solution.solve(board04);
        printf(board01);
        printf(board02);
        printf(board03);
        printf(board04);

    }

    private static void printf(char[][] board01) {
        for(int i = 0;i < board01.length;i ++) {
            for(int j = 0;j < board01[0].length;j ++) {
                System.out.print(board01[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }

    class Solution {

        public void solve(char[][] board) {
            // 长宽3以下的都不会被包围
            if(board == null || board.length < 3 || board[0].length < 3) return;

            // 分别拿出二维数组的xy以及 - 1的数
            int x = board.length;
            int y = board[0].length;
            int xd = x - 1;
            int yd = y - 1;
            char O = 'O';

            // 访问表
            int[][] visited = new int[x][y];

            // 用于统计陆地的队列
            int[][] lands = new int[x * y][2];

            // i j 从 1 开始都不遍历边界的
            for(int i = 1;i < xd;i ++) {
                for(int j = 1;j < yd;j ++) {
                    if(visited[i][j] != 1) {
                        // 队列头尾指针
                        // land begin
                        int lbegin = -1;
                        // land end
                        int lend = 0;
                        visited[i][j] = 1;

                        // 非边界元素遍历
                        if(board[i][j] == O)
                        {
                            lands[++ lbegin][0] = i;
                            lands[lbegin][1] = j;
                            boolean flag = true;

                            while(lend - lbegin >= 0)
                            {
                                int x1 = lands[lbegin][0];
                                int y1 = lands[lbegin ++][1];

                                // 触边警告,因为board04原因,所以触边依然要继续遍历
                                if(x1 == xd
                                        || x1 == 0
                                        || y1 == yd
                                        || y1 == 0)
                                {
                                    flag = false;
                                }

                                // 添加不越边约束
                                if(x1 + 1 < x && board[x1 + 1][y1] == O && visited[x1 + 1][y1] != 1) {
                                    lands[++ lend][0] = x1 + 1;
                                    lands[lend][1] = y1;
                                    visited[x1 + 1][y1] = 1;
                                }

                                // 只添加元素为 O 的
                                if(x1 - 1 >= 0 && board[x1 - 1][y1] == O && visited[x1 - 1][y1] != 1) {
                                    lands[++ lend][0] = x1 - 1;
                                    lands[lend][1] = y1;
                                    visited[x1 - 1][y1] = 1;
                                }
                                if(y1 + 1 < y && board[x1][y1 + 1] == O && visited[x1][y1 + 1] != 1) {
                                    lands[++ lend][0] = x1;
                                    lands[lend][1] = y1 + 1;
                                    visited[x1][y1 + 1] = 1;
                                }
                                if(y1 - 1 >= 0 && board[x1][y1 - 1] == O && visited[x1][y1 - 1] != 1) {
                                    lands[++ lend][0] = x1;
                                    lands[lend][1] = y1 - 1;
                                    visited[x1][y1 - 1] = 1;
                                }
                            }

                            // 如果已经是触边的联通块就不覆盖
                            if(flag) {
                                // 进行覆盖
                                while(lend >= 0) {
                                    int[] site2 = lands[lend --];
                                    board[site2[0]][site2[1]] = 'X';
                                }
                            }
                        }
                    }

                }
            }

            return;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_28033719/article/details/106825347