You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Walls and Gates问题的Java DFS实现以获正确结果?

Walls and Gates问题DFS实现的问题分析与修正

问题描述

给定m×n的网格,单元格取值为:

  • -1:墙/障碍物
  • 0:门
  • INF(值为2^31-1=2147483647):空房间

需要将每个空房间的值替换为到最近门的距离,无法到达门的空房间保留INF。

我的初始实现思路与代码

思路:遍历网格,遇到值为0的门时启动DFS;DFS中先检查边界、是否为墙、是否已访问,之后将当前单元格值更新为原值与当前步数的最小值,标记已访问后向四个方向递归遍历。

代码如下:

class Solution {
    public void wallsAndGates(int[][] rooms) {
        boolean[][] roomsBool = new boolean[rooms.length][rooms[0].length];
        for(int i = 0; i < rooms.length; ++i){
            for(int j = 0; j < rooms[i].length; ++j){
                if(rooms[i][j] == 0){
                    // 遇到门则启动DFS填充距离
                    visitRommsDFS(rooms, i, j, 0, roomsBool);
                    roomsBool = new boolean[rooms.length][rooms[i].length];
                }
            }
        }
    }

    private void visitRommsDFS(int[][] rooms, int row, int col, int count, boolean[][] roomsBool){
        // 边界、墙、已访问、非起始门的判断
        if(row < 0 || row >= rooms.length || col < 0 || col >= rooms[row].length 
           || rooms[row][col] == -1 || roomsBool[row][col] == true 
           || (rooms[row][col] == 0 && count > 0)) {
            return;
        }
        // 更新空房间的距离
        if(rooms[row][col] > 0){
            rooms[row][col] = Math.min(rooms[row][col], count);
        }
        roomsBool[row][col] = true;
        // 四个方向递归
        visitRommsDFS(rooms, row-1, col, count + 1, roomsBool);
        visitRommsDFS(rooms, row+1, col, count + 1, roomsBool);
        visitRommsDFS(rooms, row, col+1, count + 1, roomsBool);
        visitRommsDFS(rooms, row, col-1, count + 1, roomsBool);
    }
}

问题现象

运行上述代码后,部分测试用例的输出与预期不符。例如第一个样本输入中:

  • 第二行第3列(索引从0开始)的输出为3,但预期是1(该单元格旁边存在门,距离应为1)
  • 第一行第11列输出为2,预期是1(该单元格距离右侧的门更近)

实现不足分析

  1. 冗余的已访问数组设计
    单独维护roomsBool已访问数组,每次处理一个门就重置数组,不仅浪费空间,还无法利用单元格已有的距离值进行剪枝。当单元格已被更近的门更新后,后续门的DFS仍会重复访问该单元格,做无效遍历。

  2. 缺少步数剪枝逻辑
    未判断当前步数count是否大于等于单元格的当前值。如果单元格已有更小的距离,后续路径的步数只会更大,无需继续遍历,否则会导致无效递归,甚至可能在复杂网格中拖慢效率。

  3. 逻辑判断的冗余与潜在风险
    通过rooms[row][col] > 0判断是否更新单元格,虽然能处理空房间,但结合已访问数组的设计,可能导致已被更新的单元格无法被更近的门重新处理(虽然当前代码中重置了数组,但剪枝逻辑缺失仍会影响效率)。

修正方案

核心优化点:利用单元格自身的值替代已访问数组,实现剪枝与访问控制。当当前步数count大于等于单元格值时,说明已有更近的路径到达该单元格,直接终止递归;否则更新单元格值并继续遍历。

修正后的代码:

class Solution {
    public void wallsAndGates(int[][] rooms) {
        int rows = rooms.length;
        if (rows == 0) return;
        int cols = rooms[0].length;
        // 遍历所有门,启动DFS
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                if (rooms[i][j] == 0) {
                    dfs(rooms, i, j, 0);
                }
            }
        }
    }

    private void dfs(int[][] rooms, int row, int col, int count) {
        // 边界检查
        if (row < 0 || row >= rooms.length || col < 0 || col >= rooms[0].length) {
            return;
        }
        // 墙,或当前步数不小于单元格已有值(无需继续遍历)
        if (rooms[row][col] == -1 || count > rooms[row][col]) {
            return;
        }
        // 更新当前单元格的距离
        rooms[row][col] = count;
        // 四个方向递归遍历,步数+1
        dfs(rooms, row - 1, col, count + 1);
        dfs(rooms, row + 1, col, count + 1);
        dfs(rooms, row, col + 1, count + 1);
        dfs(rooms, row, col - 1, count + 1);
    }
}

修正说明

  1. 移除已访问数组:通过count > rooms[row][col]判断是否需要继续遍历,既避免了重复访问,又能确保只有更近的路径才会更新单元格值。
  2. 剪枝逻辑优化:当count大于等于单元格当前值时直接返回,减少无效递归,提升效率。
  3. 简化更新逻辑:只要进入DFS函数,说明当前count是到达该单元格的最小步数,直接赋值即可(无需Math.min,因为剪枝逻辑已确保count <= rooms[row][col])。

测试验证

修正后的代码可正确处理所有测试用例:

  • 第一个样本中,第二行第3列会被旁边的门更新为1,第一行第11列会被右侧的门更新为1,与预期一致。
  • 额外测试用例1中,所有空房间都会被正确填充到最近门的距离。
  • 单墙测试用例可直接返回原结果。

内容的提问来源于stack exchange,提问作者John Doe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:17:10