主要思路
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;
}
}
一开始也是通过全局变量来控制递归退出。
可以看到返回值的形式,代码明显简洁的多。