给你一个大小为 m x n
的二进制矩阵 grid
。
岛屿 是由一些相邻的 1
(代表土地) 构成的组合,这里的「相邻」要求两个 1
必须在 水平或者竖直的四个方向上 相邻。你可以假设grid
的四个边缘都被 0
(代表水)包围着。
岛屿的面积是岛上值为 1
的单元格的数目。
计算并返回 grid
中最大的岛屿面积。如果没有岛屿,则返回面积为 0
。
示例 1:
**输入:** grid = [[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 。
示例 2:
**输入:** grid = [[0,0,0,0,0,0,0,0]]
**输出:** 0
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j]
为 0
或 1
📺 视频题解
📖 文字题解 方法一:深度优先搜索 算法
我们想知道网格中每个连通形状的面积,然后取最大值。
如果我们在一个土地上,以 4 个方向探索与之相连的每一个土地(以及与这些土地相连的土地),那么探索过的土地总数将是该连通形状的面积。
为了确保每个土地访问不超过一次,我们每次经过一块土地时,将这块土地的值置为 0。这样我们就不会多次访问同一土地。
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution : def dfs (self, grid, cur_i, cur_j ) -> int : if cur_i < 0 or cur_j < 0 or cur_i == len (grid) or cur_j == len (grid[0 ]) or grid[cur_i][cur_j] != 1 : return 0 grid[cur_i][cur_j] = 0 ans = 1 for di, dj in [[0 , 1 ], [0 , -1 ], [1 , 0 ], [-1 , 0 ]]: next_i, next_j = cur_i + di, cur_j + dj ans += self.dfs(grid, next_i, next_j) return ans def maxAreaOfIsland (self, grid: List [List [int ]] ) -> int : ans = 0 for i, l in enumerate (grid): for j, n in enumerate (l): ans = max (self.dfs(grid, i, j), ans) return ans
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { int dfs (vector<vector<int >>& grid, int cur_i, int cur_j) { if (cur_i < 0 || cur_j < 0 || cur_i == grid.size () || cur_j == grid[0 ].size () || grid[cur_i][cur_j] != 1 ) { return 0 ; } grid[cur_i][cur_j] = 0 ; int di[4 ] = {0 , 0 , 1 , -1 }; int dj[4 ] = {1 , -1 , 0 , 0 }; int ans = 1 ; for (int index = 0 ; index != 4 ; ++index) { int next_i = cur_i + di[index], next_j = cur_j + dj[index]; ans += dfs (grid, next_i, next_j); } return ans; } public : int maxAreaOfIsland (vector<vector<int >>& grid) { int ans = 0 ; for (int i = 0 ; i != grid.size (); ++i) { for (int j = 0 ; j != grid[0 ].size (); ++j) { ans = max (ans, dfs (grid, i, j)); } } return ans; } };
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public int maxAreaOfIsland (int [][] grid) { int ans = 0 ; for (int i = 0 ; i != grid.length; ++i) { for (int j = 0 ; j != grid[0 ].length; ++j) { ans = Math.max(ans, dfs(grid, i, j)); } } return ans; } public int dfs (int [][] grid, int cur_i, int cur_j) { if (cur_i < 0 || cur_j < 0 || cur_i == grid.length || cur_j == grid[0 ].length || grid[cur_i][cur_j] != 1 ) { return 0 ; } grid[cur_i][cur_j] = 0 ; int [] di = {0 , 0 , 1 , -1 }; int [] dj = {1 , -1 , 0 , 0 }; int ans = 1 ; for (int index = 0 ; index != 4 ; ++index) { int next_i = cur_i + di[index], next_j = cur_j + dj[index]; ans += dfs(grid, next_i, next_j); } return ans; } }
复杂度分析
方法二:深度优先搜索 + 栈 算法
我们可以用栈来实现深度优先搜索算法。这种方法本质与方法一相同,唯一的区别是:
方法一通过函数的调用来表示接下来想要遍历哪些土地,让下一层函数来访问这些土地。而方法二把接下来想要遍历的土地放在栈里,然后在取出这些土地的时候访问它们。
访问每一片土地时,我们将对围绕它四个方向进行探索,找到还未访问的土地,加入到栈 stack 中;
另外,只要栈 stack 不为空,就说明我们还有土地待访问,那么就从栈中取出一个元素并访问。
[sol2-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution : def maxAreaOfIsland (self, grid: List [List [int ]] ) -> int : ans = 0 for i, l in enumerate (grid): for j, n in enumerate (l): cur = 0 stack = [(i, j)] while stack: cur_i, cur_j = stack.pop() if cur_i < 0 or cur_j < 0 or cur_i == len (grid) or cur_j == len (grid[0 ]) or grid[cur_i][cur_j] != 1 : continue cur += 1 grid[cur_i][cur_j] = 0 for di, dj in [[0 , 1 ], [0 , -1 ], [1 , 0 ], [-1 , 0 ]]: next_i, next_j = cur_i + di, cur_j + dj stack.append((next_i, next_j)) ans = max (ans, cur) return ans
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution {public : int maxAreaOfIsland (vector<vector<int >>& grid) { int ans = 0 ; for (int i = 0 ; i != grid.size (); ++i) { for (int j = 0 ; j != grid[0 ].size (); ++j) { int cur = 0 ; stack<int > stacki; stack<int > stackj; stacki.push (i); stackj.push (j); while (!stacki.empty ()) { int cur_i = stacki.top (), cur_j = stackj.top (); stacki.pop (); stackj.pop (); if (cur_i < 0 || cur_j < 0 || cur_i == grid.size () || cur_j == grid[0 ].size () || grid[cur_i][cur_j] != 1 ) { continue ; } ++cur; grid[cur_i][cur_j] = 0 ; int di[4 ] = {0 , 0 , 1 , -1 }; int dj[4 ] = {1 , -1 , 0 , 0 }; for (int index = 0 ; index != 4 ; ++index) { int next_i = cur_i + di[index], next_j = cur_j + dj[index]; stacki.push (next_i); stackj.push (next_j); } } ans = max (ans, cur); } } return ans; } };
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public int maxAreaOfIsland (int [][] grid) { int ans = 0 ; for (int i = 0 ; i != grid.length; ++i) { for (int j = 0 ; j != grid[0 ].length; ++j) { int cur = 0 ; Deque<Integer> stacki = new LinkedList <Integer>(); Deque<Integer> stackj = new LinkedList <Integer>(); stacki.push(i); stackj.push(j); while (!stacki.isEmpty()) { int cur_i = stacki.pop(), cur_j = stackj.pop(); if (cur_i < 0 || cur_j < 0 || cur_i == grid.length || cur_j == grid[0 ].length || grid[cur_i][cur_j] != 1 ) { continue ; } ++cur; grid[cur_i][cur_j] = 0 ; int [] di = {0 , 0 , 1 , -1 }; int [] dj = {1 , -1 , 0 , 0 }; for (int index = 0 ; index != 4 ; ++index) { int next_i = cur_i + di[index], next_j = cur_j + dj[index]; stacki.push(next_i); stackj.push(next_j); } } ans = Math.max(ans, cur); } } return ans; } }
复杂度分析
方法三:广度优先搜索 算法
我们把方法二中的栈改为队列,每次从队首取出土地,并将接下来想要遍历的土地放在队尾,就实现了广度优先搜索算法。
[sol3-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution : def maxAreaOfIsland (self, grid: List [List [int ]] ) -> int : ans = 0 for i, l in enumerate (grid): for j, n in enumerate (l): cur = 0 q = collections.deque([(i, j)]) while q: cur_i, cur_j = q.popleft() if cur_i < 0 or cur_j < 0 or cur_i == len (grid) or cur_j == len (grid[0 ]) or grid[cur_i][cur_j] != 1 : continue cur += 1 grid[cur_i][cur_j] = 0 for di, dj in [[0 , 1 ], [0 , -1 ], [1 , 0 ], [-1 , 0 ]]: next_i, next_j = cur_i + di, cur_j + dj q.append((next_i, next_j)) ans = max (ans, cur) return ans
[sol3-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution {public : int maxAreaOfIsland (vector<vector<int >>& grid) { int ans = 0 ; for (int i = 0 ; i != grid.size (); ++i) { for (int j = 0 ; j != grid[0 ].size (); ++j) { int cur = 0 ; queue<int > queuei; queue<int > queuej; queuei.push (i); queuej.push (j); while (!queuei.empty ()) { int cur_i = queuei.front (), cur_j = queuej.front (); queuei.pop (); queuej.pop (); if (cur_i < 0 || cur_j < 0 || cur_i == grid.size () || cur_j == grid[0 ].size () || grid[cur_i][cur_j] != 1 ) { continue ; } ++cur; grid[cur_i][cur_j] = 0 ; int di[4 ] = {0 , 0 , 1 , -1 }; int dj[4 ] = {1 , -1 , 0 , 0 }; for (int index = 0 ; index != 4 ; ++index) { int next_i = cur_i + di[index], next_j = cur_j + dj[index]; queuei.push (next_i); queuej.push (next_j); } } ans = max (ans, cur); } } return ans; } };
[sol3-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public int maxAreaOfIsland (int [][] grid) { int ans = 0 ; for (int i = 0 ; i != grid.length; ++i) { for (int j = 0 ; j != grid[0 ].length; ++j) { int cur = 0 ; Queue<Integer> queuei = new LinkedList <Integer>(); Queue<Integer> queuej = new LinkedList <Integer>(); queuei.offer(i); queuej.offer(j); while (!queuei.isEmpty()) { int cur_i = queuei.poll(), cur_j = queuej.poll(); if (cur_i < 0 || cur_j < 0 || cur_i == grid.length || cur_j == grid[0 ].length || grid[cur_i][cur_j] != 1 ) { continue ; } ++cur; grid[cur_i][cur_j] = 0 ; int [] di = {0 , 0 , 1 , -1 }; int [] dj = {1 , -1 , 0 , 0 }; for (int index = 0 ; index != 4 ; ++index) { int next_i = cur_i + di[index], next_j = cur_j + dj[index]; queuei.offer(next_i); queuej.offer(next_j); } } ans = Math.max(ans, cur); } } return ans; } }
复杂度分析