岛屿的最大面积(力扣第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循环只有两种可能:一是找到了邻接点,二是遍历完成了;但是这两种可能有耦合到一起的可能,也就是在最后一个方向的时候,找到了邻接点,那么此时就不能将栈顶元素压出。