牛客网 迷宫问题 DFS 递归 两种方式

牛客网-迷宫问题

主要思路

1. 像4个方向递归

2. 不能数组越界

3. 不能是墙

4. 在当前递归分支下,没有走过。

算24点一样,还是通过两种方式控制递归退出:

1. 通过全局变量

2. 通过函数返回值。

这里通过函数返回值,直接用静态函数就行了,并且不会有并发冲突。

公共类Coordin

package cn.line.nowcoder.huawei.hj43;

/**
 * 用于保存路径
 * 也可以直接用int[2]来实现
 */
public class Coordin {

    public static final int[][] DIRECT = new int[][]{{0, 1}, {-1, 0}, {1, 0}, {0, -1},};

    /**
     * 横坐标
     */
    public int x;
    /**
     * 纵坐标
     */
    public int y;

    public Coordin(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return String.format("(%s, %s)", x, y);
    }

    public static String toString(int x, int y) {
        return String.format("(%s, %s)", x, y);
    }
}

通过全局变量控制

package cn.line.nowcoder.huawei.hj43;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int height = sc.nextInt();
            int width = sc.nextInt();
            int[][] maze = new int[height][width];
            for (int i = 0; i < height; i++)
                for (int j = 0; j < width; j++)
                    maze[i][j] = sc.nextInt();

            System.out.println(MazeRunner.mazeString(maze));
            MazeRunner runner = new MazeRunner(maze, height, width);
            boolean found = runner.findWay();
            // 题目保证肯定能found
            if (found) {
                List<Coordin> outPath = runner.outPath;
                System.out.println(MazeRunner.path2String(outPath));
            }

        }
        sc.close();
    }

}

class MazeRunner {

    public static String mazeString(int[][] maze) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < maze.length; i++) {
            for (int j = 0; j < maze[0].length; j++)
                sb.append(maze[i][j]).append(", ");
            sb.append('\n');
        }
        return sb.substring(0, sb.length() - 3);
    }

    public static String path2String(List<Coordin> path) {
        StringBuilder sb = new StringBuilder();
        for (Coordin xy : path) {
            sb.append('(').append(xy.y).append(',').append(xy.x).append(")\n"); // 这个题目的坐标系就很怪
        }
        return sb.substring(0, sb.length() - 1);
    }


    private final int[][] maze;
    private final int height, width;

    private Stack<Coordin> pathStack = new Stack<>();

    public List<Coordin> outPath;

    private List<Coordin> curPath() {
        int size = pathStack.size();
        List<Coordin> list = new ArrayList<>(size);
        for (int i = 0; i < pathStack.size(); i++) {
            list.add(pathStack.elementAt(i));
        }
        return list;
    }

    private boolean found = false;

    public MazeRunner(int[][] maze, int height, int width) {
        this.maze = maze;
        this.height = height;
        this.width = width;
    }

    private void dfs(int x, int y) {

        maze[y][x] = 2; // 标记走过。区分墙体。
        pathStack.push(new Coordin(x, y));
//        System.out.println(String.format("/**********begin:\n%s\n%s", mazeString(maze), Coordin.toString(x, y)));

        // 找到出口
        if (x == width - 1 && y == height - 1) {
            found = true;
            outPath = curPath();
            return;
        }

        for (int i = 0; i < Coordin.DIRECT.length && !found; i++) {
            int nx = x + Coordin.DIRECT[i][0];
            int ny = y + Coordin.DIRECT[i][1];

            /*
             * 1. 没有数组越界
             * 2. 不是墙,能走
             * 3. 没走过
             */
            if (0 <= nx && nx < width && 0 <= ny && ny < height
                    && maze[ny][nx] == 0) {

                dfs(nx, ny);//进一步探测
            }
        }

        maze[y][x] = 0; // 回溯。取消走过的标记。
        pathStack.pop();
    }

    public boolean findWay() {
        dfs(0, 0);
        return found;
    }
}


通过返回值控制

package cn.line.nowcoder.huawei.hj43;

import java.util.Scanner;
import java.util.Stack;

/**
 * 递归-通过函数返回值,控制递归结束
 */
public class Main2 {

    private static String path2String(Stack<Coordin> pathStack) {

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < pathStack.size(); i++) {
            Coordin xy = pathStack.elementAt(i);
            sb.append('(').append(xy.y).append(',').append(xy.x).append(")\n"); // 这个题目的坐标系就很怪
        }
        return sb.substring(0, sb.length() - 1);
    }

    public static String mazeString(int[][] maze) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < maze.length; i++) {
            for (int j = 0; j < maze[0].length; j++)
                sb.append(maze[i][j]).append(", ");
            sb.append('\n');
        }
        return sb.substring(0, sb.length() - 3);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int height = sc.nextInt();
            int width = sc.nextInt();
            int[][] maze = new int[height][width];
            for (int i = 0; i < height; i++)
                for (int j = 0; j < width; j++)
                    maze[i][j] = sc.nextInt();

            // 题目保证肯定能found
            System.out.println(dfs(maze, new Stack<>(), 0, 0));
        }
        sc.close();
    }

    private static String dfs(int[][] maze, Stack<Coordin> pathStack, int x, int y) {

        maze[y][x] = 2; // 标记走过。区分墙体。
        pathStack.push(new Coordin(x, y));
//        System.out.println(String.format("/**********begin:\n%s\n%s", mazeString(maze), Coordin.toString(x, y)));

        // 找到出口
        if (x == maze[0].length - 1 && y == maze.length - 1) {
            return path2String(pathStack);
        }

        for (int i = 0; i < Coordin.DIRECT.length; i++) {
            int nx = x + Coordin.DIRECT[i][0];
            int ny = y + Coordin.DIRECT[i][1];

            /*
             * 1. 没有数组越界
             * 2. 不是墙,能走
             * 3. 没走过
             */
            if (0 <= nx && nx < maze[0].length && 0 <= ny && ny < maze.length && maze[ny][nx] == 0) {
                String ret = dfs(maze, pathStack, nx, ny);
                if (ret != null)
                    return ret;
            }

        }

        maze[y][x] = 0; // 回溯。取消走过的标记。
        pathStack.pop();
        return null;
    }
}

一开始也是通过全局变量来控制递归退出。

可以看到返回值的形式,代码明显简洁的多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值