岛屿的最大面积(力扣第695题)

题目:

给定一个包含了一些 0 和 1 的非空二维数组 grid 。

一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)

示例:

[[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]

对于上面这个给定矩阵应返回 6。注意答案不应该是 11 ,因为岛屿只能包含水平或垂直的四个方向的 1 。

分析:

  要求的是最大的岛屿面积,这个面积是按照组成岛屿的1的个数来计算的,而相邻的方向设置为水平和垂直。其实就是从某个值为1的点出发,从水平和垂直四个方向上向相邻的点行走,可以最多路过多少个值为1的点。那我么就可以利用深度优先遍历算法来解决:

  DFS的算法思想就是:从某一点出发,到达其某个邻接点后,再从这个邻接点出发,走向邻接点的邻接点,直到最终无路可走,然后再向上后退,走其他的邻接点,继续向下一直走,最终遍历完所有的点为止。

  那我们遍历这个二维数组,设置一个访问记录数组,记录数组中的点是否被访问,访问过的点就不能再访问了,每遍历到值为1的点时,它未被访问过,那么就从这个点出发,进行深度优先遍历,计算它能遍历的总的点的个数,再与当前最大值进行比较,如果比当前最大值大,那么就替换当前最大值,否则继续遍历数组中其他值为1的点。

  对于二维数组中的某一点(i,j),其可以走的方向有四个,可表示为:(1,0)、(-1,0)、(0,1)、(0,-1)

代码:

    public int maxAreaOfIsland(int[][] grid) {

        if (grid == null){
            return 0;
        }
        int col = grid[0].length;
        int row = grid.length;

        boolean[][] isVisited = new boolean[row][col];
        int max_res = 0;
        for (int i = 0; i < row; i++) {

            for (int j = 0; j < col; j++) {

                if (!isVisited[i][j] && grid[i][j] == 1){

                    max_res = Math.max(max_res,curAreadByDFS(grid,i,j,isVisited));
                }
            }
        }
        return max_res;
    }

    private int curAreadByDFS(int[][] grid,int r,int c,boolean[][] isVisited){

        int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};
        Stack<Pair<Integer, Integer>> stack = new Stack<>();
        int length = 1;
        stack.push(new Pair<>(r,c));
        isVisited[r][c] = true;
        while (!stack.isEmpty()){
            Pair<Integer, Integer> node = stack.peek();
            int currow = node.getKey();
            int curcol = node.getValue();

            int flag = 0;
            for (int[] dir : dirs) {

                int nex_r = dir[0] + currow;
                int nex_c = dir[1] + curcol;
                if (nex_c < 0 || nex_r >= grid.length || nex_r < 0 || nex_c >= grid[0].length){
                    continue;
                }
                if (grid[nex_r][nex_c] == 1 && !isVisited[nex_r][nex_c]){
                    stack.push(new Pair<>(nex_r,nex_c));
                    isVisited[nex_r][nex_c] = true;
                    length++;
                    flag = 1;
                    break;
                }
            }
            if (flag == 0){
                stack.pop();
            }
        }

        return length;
    }

  我采用的DFS算法是通过非递归的形式实现的,借助于栈,实现DFS。设置变量flag的原因是为了通知何时可以将当前访问的顶点压出栈,我们遍历当前顶点的相邻点的时候,是从当前顶点的四个相邻位置遍历的,四个方向遍历完毕时,如果未找到当前顶点可以继续向下走的顶点,那么说明此时这个顶点已经无路可走,那么它也就没有必要再留到栈里面,而是向上返回到当前顶点的前一步顶点,遍历其前一步顶点是否有路可走。

  如果通过判断方向选择遍历完毕来说明要压出栈,是会出问题的,因为退出方向遍历的for循环只有两种可能:一是找到了邻接点,二是遍历完成了;但是这两种可能有耦合到一起的可能,也就是在最后一个方向的时候,找到了邻接点,那么此时就不能将栈顶元素压出。

原文地址:https://www.cnblogs.com/yxym2016/p/13155131.html