给你一个大小为 m × n m \times n m×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
提示:
这里我们使用了一个小技巧,对于四个方向的遍历,可以创造一个数组 [-1, 0, 1, 0, -1],每相邻两位即为上下左右四个方向之一。
在辅函数里,一个一定要注意的点是辅函数内递归搜索时,边界条件的判定。边界判定一般有两种写法,一种是先判定是否越界,只有在合法的情况下才进行下一步搜索(即判断放在调用递归函数前);另一种是不管三七二十一先进行下一步搜索,待下一步搜索开始时再判断是否合法(即判断放在辅函数第一行)。我们这里分别展示这两种写法。
Leetcode 官方题解:
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;
}
};
我自己的:
class Solution {
void DFS(vector<vector<int>>& grid, int x, int y, int& area){
if(0 > x || x >= grid[0].size() || y >= grid.size() || 0 > y) return;
if(grid[y][x] == 1){
// 上下左右
area += 1;
grid[y][x] = 0; // 置为0防止再次访问该点
DFS(grid, x-1, y, area);
DFS(grid, x+1, y, area);
DFS(grid, x, y-1, area);
DFS(grid, x, y+1, area);
}
}
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int ans = 0, area, yn = grid.size(), xn = grid[0].size();
for(int y = 0; y < yn; y++){
for(int x = 0; x < xn; x++){
if(grid[y][x] == 1){
area = 0;
DFS(grid, x, y, area);
ans = ans < area? area: ans;
}
}
}
return ans;
}
};
时间复杂度: O ( m × n ) O(m×n) O(m×n)。其中 m m m 是给定网格中的行数, n n n 是列数。我们访问每个原本为1的网格最多一次。
空间复杂度: O ( m × n ) O(m \times n) O(m×n),递归的深度最大可能是整个网格的大小,因此最大可能使用 O ( m × n ) O(m \times n) O(m×n) 的栈空间。
原理与方法一相同,只是实现方式采用了迭代而不是递归,并使用栈辅助实现。
Leetcode 官方题解:
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;
}
};
我自己的:
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int ans = 0, area, yn = grid.size(), xn = grid[0].size();
stack<pair<int, int>> island;
pair<int, int> tmp;
for(int y = 0; y < yn; y++){
for(int x = 0; x < xn; x++){
if(grid[y][x] == 1){
area = 0;
island.push(make_pair(y, x));
while(!island.empty()){
tmp.first = island.top().first;
tmp.second = island.top().second;
island.pop();
if(grid[tmp.first][tmp.second] != 1) continue;
grid[tmp.first][tmp.second] = 0;
area++;
if(tmp.second-1 >= 0) island.push(make_pair(tmp.first, tmp.second-1));
if(tmp.second+1 < xn) island.push(make_pair(tmp.first, tmp.second+1));
if(tmp.first-1 >= 0) island.push(make_pair(tmp.first-1, tmp.second));
if(tmp.first+1 < yn) island.push(make_pair(tmp.first+1, tmp.second));
}
ans = max(area, ans);
}
}
}
return ans;
}
};
时间复杂度: O ( m × n ) O(m \times n) O(m×n)。其中 m m m 是给定网格中的行数, n n n 是列数。我们访问每个原本为1的网格最多一次。
空间复杂度: O ( m × n ) O(m \times n) O(m×n),栈中最多会存放所有的土地,土地的数量最多为 m × n m \times n m×n 块,因此使用的空间为 O ( m × n ) O(m \times n) O(m×n)。
把方法二中的栈改为队列,每次从队首取出土地,并将接下来想要遍历的土地放在队尾,就实现了广度优先搜索算法。
Leetcode 官方题解:
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;
}
};
我自己的:
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int ans = 0, area, yn = grid.size(), xn = grid[0].size();
queue<pair<int, int>> island;
pair<int, int> tmp;
for(int y = 0; y < yn; y++){
for(int x = 0; x < xn; x++){
if(grid[y][x] == 1){
area = 0;
island.push(make_pair(y, x));
while(!island.empty()){
tmp.first = island.front().first;
tmp.second = island.front().second;
island.pop();
if(grid[tmp.first][tmp.second] != 1) continue;
grid[tmp.first][tmp.second] = 0;
area++;
if(tmp.second-1 >= 0) island.push(make_pair(tmp.first, tmp.second-1));
if(tmp.second+1 < xn) island.push(make_pair(tmp.first, tmp.second+1));
if(tmp.first-1 >= 0) island.push(make_pair(tmp.first-1, tmp.second));
if(tmp.first+1 < yn) island.push(make_pair(tmp.first+1, tmp.second));
}
ans = max(area, ans);
}
}
}
return ans;
}
};
时间复杂度: O ( m × n ) O(m×n) O(m×n)。其中 m m m 是给定网格中的行数, n n n 是列数。我们访问每个原本为1的网格最多一次。
空间复杂度: O ( m × n ) O(m \times n) O(m×n),队列中最多会存放所有的土地,土地的数量最多为 m × n m \times n m×n 块,因此使用的空间为 O ( m × n ) O(m \times n) O(m×n)。