Java中多维数组DFS本质是将数组视为隐式图,每个位置为节点、相邻位置为邻边;需防越界、防重复访问,并依目标调整逻辑:1.递归模板含边界/状态检查、标记、四向递归;2.迭代法用栈模拟,以dx/dy数组控制方向;3.常见变体包括岛屿计数、最大面积、路径存在性及带状态搜索;4.需注意不规则数组列长、栈溢出风险与visited复用。

Java 中在多维数组中进行深度优先搜索(DFS)遍历,本质是把数组当作隐式图来处理:每个位置(如 grid[i][j])是一个节点,其上下左右(有时含对角线)相邻位置是它的邻接节点。关键在于避免重复访问、防止越界、明确搜索目标(如找连通区域、岛屿数量、路径是否存在等)。
下面分几个实用角度说明:
1. 基础模板:二维数组上的递归 DFS
适用于网格类问题(如岛屿、迷宫、洪水填充等)。核心三步:标记已访问 → 探索四个方向 → 递归深入。
public void dfs(int[][] grid, int i, int j, boolean[][] visited) {
// 边界检查 + 访问状态检查
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length
|| visited[i][j] || grid[i][j] == 0) { // 假设 0 表示不可通行/非目标
return;
}
visited[i][j] = true; // 标记为已访问(或直接改 grid[i][j] = 0 实现“原地标记”)
// 四个方向:上、下、左、右
dfs(grid, i - 1, j, visited);
dfs(grid, i + 1, j, visited);
dfs(grid, i, j - 1, visited);
dfs(grid, i, j + 1, visited);
}注意:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
-
visited数组用于防止重复进入同一格子;也可用“染色法”原地修改(如将1改为2),节省空间; - 若网格含障碍(如
0是墙,1是陆地),条件中需排除障碍; - 若需统计连通块大小,可在进入时
count++,作为参数传递或用闭包变量。
2. 非递归实现:用栈模拟 DFS(避免栈溢出)
适合超大网格或深度受限场景。手动维护坐标栈,每次弹出一个点,压入其未访问邻居。
public void dfsIterative(int[][] grid, int startI, int startJ, boolean[][] visited) {
Stack<int[]> stack = new Stack<>();
stack.push(new int[]{startI, startJ});
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
while (!stack.isEmpty()) {
int[] cur = stack.pop();
int i = cur[0], j = cur[1];
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length
|| visited[i][j] || grid[i][j] == 0) {
continue;
}
visited[i][j] = true;
// 将四个邻居压栈(顺序影响遍历方向,但不影响连通性)
for (int k = 0; k < 4; k++) {
int ni = i + dx[k], nj = j + dy[k];
stack.push(new int[]{ni, nj});
}
}
}注意:
立即学习“Java免费学习笔记(深入)”;
-
continue替代return,因栈中可能存有无效坐标; - 压栈顺序决定“最后访问谁”——比如先压右再压下,实际会先处理下(LIFO);
- 不用担心重复压栈,靠
visited在开头拦截。
3. 实际应用中的常见变体
-
岛屿数量(LeetCode 200):外层遍历每个格子,遇到未访问的
1就启动一次 DFS,计数器加一; - 最大岛屿面积:DFS 返回当前连通块大小,取全局最大值;
-
判断是否存在路径(起点→终点):DFS 中加入
if (i == endI && j == endJ) return true;,提前终止; -
带状态的 DFS(如带步数、钥匙、时间):此时不能只用二维
visited,需升级为三维甚至四维(如visited[i][j][mask]),表示在位置(i,j)持有钥匙集合mask是否来过。
4. 安全与效率提醒
- 多维数组维度不一致时(如
grid[i]长度不同),务必用grid[i].length而非grid[0].length判断列数; - 递归 DFS 深度过大(如 10⁴×10⁴ 网格全连通)可能触发
StackOverflowError,此时必须改用栈迭代; - 若允许多次查询(如动态更新网格后重搜),建议封装成类,复用
visited数组或重置逻辑。
不复杂但容易忽略。

















