【DFS解决floodfill算法】岛屿数量

文章摘要:

  • 题目要求在给定的二维矩阵中,统计由相邻陆地('1')组成的岛屿数量,其中相邻指水平或垂直方向相连。通过深度优先搜索(DFS)解决:遍历矩阵,每发现未被访问的陆地时标记为已访问并计数,然后递归搜索其四周相邻陆地。全局变量记录矩阵信息及访问状态,方向数组简化四向搜索。无需回溯或剪枝,当所有陆地访问完毕即返回岛屿总数。代码实现中,主函数初始化并遍历矩阵,DFS函数处理相邻陆地标记,确保每个岛屿只统计一次。

文章目录

题目链接:200. 岛屿数量

一、题目解析

题目给我们一个由 1(陆地)0(水) 组成的的二维网格 grid,我们需要计算网格中岛屿的数量

岛屿总是被水包围,并且每座岛屿只能由水平方向 和/或竖直方向相邻的陆地连接形成。

示例1,题目给出的二维网格 grid 是:

1 1 1 1 0
1 1 0 1 0
1 1 0 0 0
0 0 0 0 0

那么岛屿只有一块:

1 1 1 1 0
1 1 0 1 0
1 1 0 0 0
0 0 0 0 0

示例2,题目给出的二维网格 grid:

1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

则有三块岛屿:

1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

二、算法原理 + 代码实现

题目的本质是在二维矩阵中搜索,因此我们可以:

  1. 遍历矩阵,当找到一个未被标记过的岛屿时就更新岛屿的数量并标记,
  2. 然后从这个位置开始向四周深度优先搜索相邻的未被标记过的陆地,直到搜索不到陆地为止。
  3. 当矩阵遍历完毕,返回所记录的岛屿的数量即可

全局变量

为了 dfs 函数递归方便,将矩阵 grid 改成全局变量;mn 记录矩阵的大小;ret 用于记录岛屿的数量。

布尔类型的数组 visit 则用于标记已经发现的岛屿和陆地,防止重复计入;dxdy 方向数组,用于访问指定位置的上下左右四个方向。

java 复制代码
char[][] grid;
int m, n, ret;
boolean[][] visit;
int[] dx = {0, 0, -1, 1};
int[] dy = {-1, 1, 0, 0};

dfs 函数

函数头

dfs 函数的任务是从指定位置出发,访问它的四个方向,因此函数的参数是 rowcol,表示某位置的坐标。

java 复制代码
dfs(int row, int col);

函数体

我们在 dfs 函数体中要做的事情就是:从指定位置(坐标 row, col )出发,逐一访问该位置的上、下、左、右四个方向的位置,看看是否是未记录过的陆地,如果是,就继续递归深搜,否则不进行深搜。

具体就是循环四次然后计算出下一个位置的坐标,判断坐标是否合法,若合法,就进一步判断:

  1. 该坐标在 grid 矩阵中的值是否是 '1' ------ 该位置是陆地
  2. 该坐标的在 visit 中的值是否不等于 "true" ------ 该位置未被标记过

若以上两个条件都满足,就继续递归深搜。

细节问题

回溯

本题不需要回溯操作,我们标记一个岛屿之后不需要将其状态修改回去。

剪枝

由于解法是基于暴搜的,每一个节点都会被遍历到,因此不涉及到剪枝操作。

递归出口

当所有的岛屿都被遍历到并记录之后,就直接退出递归,无需手动设置递归出口。

代码实现

java 复制代码
class Solution {
	char[][] grid;
	int m, n, ret;
	boolean[][] visit;
	int[] dx = {0, 0, -1, 1};
	int[] dy = {-1, 1, 0, 0};

    public int numIslands(char[][] givenGrid) {
        grid = givenGrid; m = grid.length; n = grid[0].length;
        visit = new boolean[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1' && !visit[i][j]) {
                    // 找到未被标记过的岛屿,标记该岛屿并更新岛屿数量
                    visit[i][j] = true; ret++;
                    dfs(i, j); // 从该位置开始向四周寻找相邻的陆地
                }
            }
        }

        return ret;
    }

    private void dfs(int row, int col) {
        for (int k = 0; k < 4; k++) {
            int x = row + dx[k], y = col + dy[k];
            if (x >= 0 && x < m && y >= 0 && y < n) {
                if (grid[x][y] == '1' && !visit[x][y]) {
                    // 找到未被标记过的相邻陆地
                    visit[x][y] = true;
                    dfs(x, y);
                }
            }
        }
    }
}

文章到这里就告一段落了,若有错误请尽管指出~

相关推荐
唐青枫10 小时前
Java 虚拟线程实战指南:从 Thread API 到 Spring Boot 高并发应用
java
To_OC18 小时前
从一次栈溢出报错说起,我把递归彻底扒明白了
javascript·算法·程序员
千纸鹤安安1 天前
千问Qwen-AgentWorld来了:一个语言模型搞定七大Agent场景,GPT-5.4都输了
算法
白鲸开源1 天前
Apache SeaTunnel Zeta Engine 的 Basic Auth 是怎么工作的?
java·vue.js·github
白鲸开源1 天前
一文读懂DolphinScheduler插件机制:如何轻松扩展任务类型与数据源
java·架构·github
七牛开发者1 天前
MCP 到底是什么?为什么 Agent 都想接上它
算法·aigc·agent
用户298698530141 天前
Java 实现 Word 文档文本查找与高亮标注
java·后端
宇宙之一粟1 天前
乐企版式文件生成平台
java·后端·python