上一篇博客:LeetCode 101.对称二叉树(DFS、BFS)
写在前面:大家好!我是
ACfun
,我的昵称来自两个单词Accepted
和fun
。我是一个热爱ACM的蒟蒻。最近萌生了刷LeetCode的想法,所以我打算从LeetCode简单的题目开始做起,攻陷LeetCode。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭!
用知识改变命运,用知识成就未来!加油 (ง •̀o•́)ง (ง •̀o•́)ง
原题链接:LeetCode 200.岛屿数量
题目信息
题目描述
给你一个由 '1'
(陆地)和 '0'
(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例
示例1
示例2
题解
这道题目是一个经典的 Flood fill 算法(洪水填充算法)
,从一个起始节点开始把附近与其连通的节点提取出或填充成不同颜色颜色,直到封闭区域内的所有节点都被处理过为止,是从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典算法。因为其思路类似洪水从一个区域扩散到所有能到达的区域而得名。
对于这类题目我们可以使用 深度优先搜索(DFS)
也可以使用 广度优先搜索(BFS)
来解决,洪水填充算法实现最常见有四邻域像素填充法,八邻域像素填充法,基于扫描线的像素填充方法。根据实现又可以分为递归与非递归(基于栈)。
DFS解法
解题思路
首先我们遍历整个地图,当我们遇到 '1'
,即当前地方为陆地的时候我们就启用深度优先搜索开始向四周搜索地图,在遍历的时候我们首先将当前遍历的位置的数据由 '1'
改为 '0'
表示我们已经遍历过,然后向四周开始搜索,这里我们按照 上、右、下、左 的顺序深度优先遍历地图,如果当前遍历的点在地图内并且为陆地的时候我们就继续以当前的点为起点继续启动深度优先搜索函数搜索,直到四周都为水时就结束 dfs()
,并将陆地数加一,然后继续遍历下一块陆地,直到遍历完这个地图。
解题代码
class Solution {
public:
vector<vector<char>> g;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int numIslands(vector<vector<char>>& grid) {
g = grid;
int ans = 0;
for (int i = 0; i < g.size(); i++) {
for (int j = 0; j < g[i].size(); j++) {
if (g[i][j] == '1') {
dfs(i, j);
ans++;
}
}
}
return ans;
}
void dfs(int x, int y) {
g[x][y] = '0';
for (int i = 0; i < 4; i++) {
int a = x + dx[i], b = y + dy[i];
if (inmap(a,b) && g[a][b] == '1') {
dfs(a, b);
}
}
}
bool inmap(int x, int y) {
return x >= 0 && x < g.size() && y >= 0 && y < g[x].size();
}
};
时间复杂度
时间复杂度:O(M*N),其中 M
和 N
分别为行数和列数。
提交结果
BFS解法
解题思路
与DFS一样我们也需要遍历整个地图,但是不同的是我们不再使用 栈
来维护而是使用 队列
进行维护。如果当前我们遍历的点为 '1'
那么我们就将当前位置标记为 '0'
表示我们已经遍历过然后将该位置的坐标入队,然后判断队列是否为空,如果不为空就将当前队列的队头元素出队并搜索该点四周有没有符合条件的点,如果有那么将其坐标入队。当队列中的元素为空时那么本次BFS搜索结束,我们找到了一个岛屿,将岛屿的数量加一。继续搜索遍历整个地图,直到遍历完整个地图。最后我们得到的就是岛屿的所有数量。
解题代码
class Solution {
public:
vector<vector<char>> g;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
int numIslands(vector<vector<char>>& grid) {
g = grid;
int ans = 0;
for (int i = 0; i < g.size(); i++) {
for (int j = 0; j < g[i].size(); j++) {
if (g[i][j] == '1') {
bfs(i, j);
ans++;
}
}
}
return ans;
}
void bfs(int x, int y) {
g[x][y] = '0';
queue<pair<int, int>> q;
q.push({x, y});
while (!q.empty()) {
pair<int, int> xy = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int x1 = xy.first + dx[i], y1 = xy.second + dy[i];
if (inmap(x1, y1) && g[x1][y1] == '1') {
q.push({x1, y1});
g[x1][y1] = '0';
}
}
}
}
bool inmap(int x, int y) {
return x >= 0 && x < g.size() && y >= 0 && y < g[0].size();
}
};
时间复杂度
时间复杂度:O(M*N),其中 M
和 N
分别为行数和列数。
提交结果
参考资料:洪水填充(Flood fill)算法
未完待续,持续更新中……