力扣题目链接
代码随想录文章链接
在代码随想录中写了深搜和广搜两个思路,并且它使用的是 ACM 模式。在这里,我们从 leetcode 的核心代码的角度来讲解核心思路。
首先我们分析题目,题目其实意思就是说,所有的连接起来的 “1” 表示一座岛屿,然后 0 是水流,其实我们最主要的逻辑就是:
- 搜索整个网格,只要遇到没有访问过的陆地,马上结果 +1;
- 我们要把相邻的陆地全部打上“已经访问” 的标记。
- 随后我们继续开始搜索网格。
在基础的思路分析中,搜索网格的代码很简单,两个 for 循环,但是我们如何把相邻陆地都打上 “已访问” 标记呢?那就离不开我们的搜索算法来:DFS、BFS。
DFS
在这个代码中有一个小技巧:那就是把终止条件写在了调用 dfs 的地方:
private:
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 顺序为:右, 下, 左, 上(逆时针)
void dfs(const vector<vector<char>>& grid
, vector<vector<bool>>& visited
, int x
, int y) {
for (int i = 0; i < 4; i++) {
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
if (nextx < 0 || nextx >= grid.size()
|| nexty < 0 || nexty >= grid[0].size())
continue;
if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') {
visited[nextx][nexty] = true;
dfs(grid, visited, nextx, nexty);
}
}
}
代码的核心流程如下:
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[0].size(); j++) {
if (!visited[i][j] && grid[i][j] == '1') {
res++;
visited[i][j] = true;
dfs(grid, visited, i, j);
}
}
}
BFS
广度优先搜索主打的就是一个 队列 + 迭代
这里需要注意的一个问题就是,只要加入队列,我们应该立即标记该节点已经走过。
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 四个方向
void bfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
queue<pair<int, int>> que;
que.push({x, y});
visited[x][y] = true; // 只要加入队列,立刻标记
while(!que.empty()) {
pair<int ,int> cur = que.front(); que.pop();
int curx = cur.first;
int cury = cur.second;
for (int i = 0; i < 4; i++) {
int nextx = curx + dir[i][0];
int nexty = cury + dir[i][1];
if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过
if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {
que.push({nextx, nexty});
visited[nextx][nexty] = true; // 只要加入队列立刻标记
}
}
}
}