题目来源:200:https://leetcode.com/problems/number-of-islands/description/
695:https://leetcode.com/problems/max-area-of-island/description/
BFS\DFS巩固。关联旧题。小题升级。
200. Number of Islands
题目大意
在字符“0”和“1”组成的矩阵中,“0”代表海水,“1”代表岛屿,连在一起的小岛屿组成一个大岛(对角线不算连在一起)。
找出大岛的总个数。
例
11000
11000
00100
00011
Answer: 3
思路
- 利用一个visited二维数组来标志一个数是否被访问过。
- 利用广度优先搜索来找连在一起的小岛屿所组成的一个大岛。
- 统计广度优先搜索的次数,即大岛的总个数。
代码
#define NMAX 1000
int visited[NMAX][NMAX] = {0};
void bfs(char** grid, int gridRowSize, int gridColSize, int i, int j) {
if (i >= 0 && i < gridRowSize && j >= 0 && j < gridColSize && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j - 1);
bfs(grid, gridRowSize, gridColSize, i, j + 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
}
}
int numIslands(char** grid, int gridRowSize, int gridColSize) {
for (int i = 0; i < NMAX; i++)
for (int j = 0; j < NMAX; j++)
visited[i][j] = 0;
int count = 0;
for (int i = 0; i < gridRowSize; i++) {
for (int j = 0; j < gridColSize; j++) {
if (visited[i][j] == 0 && grid[i][j] == '1') {
count++;
bfs(grid, gridRowSize, gridColSize, i, j);
}
}
}
return count;
}
关联的旧题
200这题可以说是博客第四周记录的题目547. Friend Circles的升级版。
547也是一道与图有关的题目,可简化成找出无向图中连通图的个数。
相较之下,200与典型的图不太相同,不能简单地说有向无向,毕竟行列数都不一致。为了解决行列数不一致的问题,我们只好把visited数组从一维数组改为二维数组,用于记录grid中的每个点。难度有所提升。
遇到的问题
处理下标的时候,想到grid的边界和中间应该采用不同的递归式。比如grid[0][0]就只用找grid[0][1]、grid[1][0],并不用上下左右都找一边,找了也是越界。于是写了一下几个边界处理:
if (i > 0 && i < gridRowSize-1 && j > 0 && j < gridColSize-1 && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j - 1);
bfs(grid, gridRowSize, gridColSize, i, j + 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
} else if (i == 0 && j > 0 && j < gridColSize-1 && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i, j - 1);
bfs(grid, gridRowSize, gridColSize, i, j + 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
} else if (i > 0 && i < gridRowSize-1 && j == 0 && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j + 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
} else if (i == 0 && j == 0 && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i, j + 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
} else if (i == gridRowSize-1 && j > 0 && j < gridColSize-1 && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j - 1);
bfs(grid, gridRowSize, gridColSize, i, j + 1);
} else if (i > 0 && i < gridRowSize-1 && j == gridColSize-1 && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j - 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
} else if (i == gridRowSize-1 && j == gridColSize-1 && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j - 1);
}
但是关心则乱,一通处理下来,反而使算法的逻辑不清楚了。运行了一下,错误bug一堆。但是这么一大坨代码,自己根本都不想看。
后来静下来捋一捋,发现越界的行列参数i、j根本传不进if语句,一大坨可以直接简化成:
if (i >= 0 && i < gridRowSize && j >= 0 && j < gridColSize && !visited[i][j] && grid[i][j] == '1') {
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j - 1);
bfs(grid, gridRowSize, gridColSize, i, j + 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
}
嗯,舒服多了。
~ o( ̄▽ ̄)o~
(200升级版)695. Max Area of Island
题目大意
在0和1组成的矩阵中,0代表海水,1代表岛屿,连在一起的小岛屿组成一个大岛(对角线不算连在一起)。
找出所有大岛中最大的岛,并输出组成该大岛的小岛屿的个数。
例
[[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]]
Given the above grid, return 6.
思路
这题其实和200是一模一样的,只不过多了一步“输出组成该大岛的小岛屿的个数”。这很容易解决,只要加一个计数器,在每次扫描点的时候把该连通区域内扫过的点的个数累加便可。
代码
为了方便,这里的计数器用全局变量。
#include <stdio.h>
#include <stdlib.h>
#define NMAX 51
int visited[NMAX][NMAX] = {0};
int count = 0;
void bfs(int** grid, int gridRowSize, int gridColSize, int i, int j) {
if (i >= 0 && i < gridRowSize && j >= 0 && j < gridColSize && !visited[i][j] && grid[i][j] == 1) {
count++;
visited[i][j] = 1;
bfs(grid, gridRowSize, gridColSize, i - 1, j);
bfs(grid, gridRowSize, gridColSize, i, j - 1);
bfs(grid, gridRowSize, gridColSize, i, j + 1);
bfs(grid, gridRowSize, gridColSize, i + 1, j);
}
}
int maxAreaOfIsland(int** grid, int gridRowSize, int gridColSize) {
for (int i = 0; i < NMAX; i++)
for (int j = 0; j < NMAX; j++)
visited[i][j] = 0;
int max = 0;
for (int i = 0; i < gridRowSize; i++) {
for (int j = 0; j < gridColSize; j++) {
count = 0;
if (visited[i][j] == 0 && grid[i][j] == 1) {
bfs(grid, gridRowSize, gridColSize, i, j);
if (count > max) max = count;
}
}
}
return max;
}
遇到的问题
没啥大问题
- 不要把max和count混淆。
- 每一次做bfs前要把count清零。