【面试】如何找到迷宫出口
一、問題描述
給出如下的矩陣
1 1 1 1
0 0 0 1
1 9 0 0
1 1 1 1
其中1代表此位置是可以通過的,0代表此位置是不可通過的,要從起點(diǎn)開始,確定是否存在這樣一條路徑,可以從起點(diǎn)找到數(shù)字9。也就是找到這樣一條路徑1->1->1 ...... ->9。這個問題是尋找迷宮出口的變形。可以將9看成是迷宮的出口,而給出的開始位置是迷宮的入口,尋找一條路徑。
二、問題求解
當(dāng)矩陣階數(shù)不是太大的時,可以使用遞歸來求解,但是,當(dāng)矩陣的階數(shù)變得很大時,則需要使用另外的方法進(jìn)行計(jì)算,也就是采用棧來進(jìn)行求解。
下面是兩種解決方法
1.當(dāng)矩陣階數(shù)較小時,采用遞歸進(jìn)行求解,這種方式只是用來開拓思路,解此問題存在一定的局限性。
源代碼如下:
import java.util.Scanner;
public class MatrixPath {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String line = scan.nextLine(); //輸入行和列
String[] lines = line.split("\s+");//分離行和列
int row = Integer.parseInt(lines[0]);
int col = Integer.parseInt(lines[1]);
int[][] matrix = new int[row + 2][col + 2]; //將外層包圍一層0元素
footPrints = new boolean[row + 2][col + 2];
endPrints = new boolean[row + 2][col + 2];
for(int i = 0; i < row; i++) { //初始化數(shù)組元素
line = scan.nextLine();
lines = line.split("\s");
for(int j = 0; j < lines.length; j++) {
matrix[i + 1][j + 1] = Integer.parseInt(lines[j]);
}
}
scan.close();
int startX = 1; //入口橫坐標(biāo)
int startY = 1; //入口縱坐標(biāo)
System.out.println(exsitPath(startX, startY, row, col, matrix) + " ");
}
public static boolean exsitPath(int x, int y, int row, int col, int[][] matrix) {
if(x < 0 || y < 0 || x >= row || y >= col)
return false;
if(matrix[x][y] == 9)
return true;
if(matrix[x][y] == 0)
return false;
if(exsitPath(x + 1, y, row, col, matrix) || exsitPath(y - 1, x, row, col, matrix) || exsitPath(x, y - 1, row, col, matrix) || exsitPath(x, y + 1, row, col, matrix))
return true;
return false;
}
}
測試用例:
3 3
1 1 1
1 9 1
0 1 1
輸出結(jié)果為:true
測試用例:
4 4
1 1 1 1
0 0 0 1
0 0 1 1
9 1 1 1
輸出結(jié)果:java.lang.StackOverflowError,堆棧溢出
2.使用遞歸的方法要選擇好測試用例,很可能因?yàn)闇y試用例的選取不恰當(dāng)而造成堆棧溢出。遞歸只是為了開拓思路而已,下面使用棧結(jié)構(gòu)來解決堆棧溢出的問題。
源代碼如下:
package com.leesf.Main;
import java.util.ArrayList;
import java.util.Scanner;
class Position {//位置信息
private int x;
private int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
class Item {//棧中元素類型
private int order; //第幾步
private Position seat; //位置
private int value; //對應(yīng)的值
private int di; //方位
public Item(int order, Position seat, int value, int di) {
this.order = order;
this.seat = seat;
this.value = value;
this.di = di;
}
public int getOrder() {
return order;
}
public Position getSeat() {
return seat;
}
public int getDi() {
return di;
}
public int getValue() {
return value;
}
public void setDi(int di) {
this.di = di;
}
}
class MyStack<T> {//定義棧結(jié)構(gòu)
private static int index = -1;
private ArrayList<T> array;
public MyStack() {
array = new ArrayList<T>();
}
public void push(T item) {
array.add(item);
index++;
}
public T pop() {
T result = array.get(index);
array.remove(index);
index--;
return result;
}
public boolean isEmpty() {
if(index != -1)
return false;
else
return true;
}
}
public class MatrixPath {
private static boolean[][] footPrints; //留下腳印
private static boolean[][] endPrints; //留下不能通過印記
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String line = scan.nextLine(); //輸入行和列
String[] lines = line.split("\s+");//分離行和列
int row = Integer.parseInt(lines[0]);
int col = Integer.parseInt(lines[1]);
int[][] matrix = new int[row + 2][col + 2]; //將外層包圍一層0元素
footPrints = new boolean[row + 2][col + 2];
endPrints = new boolean[row + 2][col + 2];
for(int i = 0; i < row; i++) { //初始化數(shù)組元素
line = scan.nextLine();
lines = line.split("\s");
for(int j = 0; j < lines.length; j++) {
matrix[i + 1][j + 1] = Integer.parseInt(lines[j]);
}
}
scan.close();
int startX = 1; //入口橫坐標(biāo)
int startY = 1; //入口縱坐標(biāo)
System.out.println(exsitPath(startX, startY, row, col, matrix) + " ");
//System.out.println(exsitPath(startX, startY, matrix) + " ");
}
//判斷是否存在路徑
public static boolean exsitPath(int x, int y, int[][] matrix) {
MyStack<Item> stack = new MyStack<Item>();
//當(dāng)前的位置
Position curPos = new Position(x, y);
//開始第一步
int curStep = 1;
do {
if(pass(curPos, matrix)) { //該位置是可通過的
System.out.println("x - y = " + curPos.getX() + " - " + curPos.getY());
footPrint(curPos);//留下腳印
Item item = new Item(curStep, curPos, matrix[curPos.getX()][curPos.getY()], 1);
stack.push(item);//將該可通位置放入棧中
if(item.getValue() == 9) {//如果已經(jīng)找到目標(biāo),則返回
System.out.println("總共花費(fèi)了" + curStep + "步, 找到目標(biāo)");
return true;
}
curPos = nextPos(curPos, 1);//試探下一步,即東邊的,但是不放入棧中
curStep++;//步數(shù)加1
} else {//改位置不可通過
if(!stack.isEmpty()) {//棧不為空
Item item = stack.pop();//出棧
while(item.getDi() == 4 && !stack.isEmpty()) {//留下了腳印的個數(shù)加上不可通過的個數(shù)之和為4,進(jìn)行出棧處理
markPrint(item.getSeat());//留下不可通過印記并進(jìn)行出棧處理
item = stack.pop();//出棧
}
if(item.getDi() < 4) {//四個方向還未試探完
item.setDi(item.getDi() + 1);//換下一個方向進(jìn)行試探
stack.push(item);//入棧
curPos = nextPos(item.getSeat(), item.getDi());//試探下一個位置
}
}
}
} while(!stack.isEmpty());
System.out.println("總共花費(fèi)了" + curStep + "步,沒有找到目標(biāo)");
return false;
}
public static boolean pass(Position curPos, int[][] matrix) {
if(matrix[curPos.getX()][curPos.getY()] != 0 && endPrints[curPos.getX()][curPos.getY()] == false && footPrints[curPos.getX()][curPos.getY()] == false)
return true;
else
return false;
}
public static void footPrint(Position curPos) {
footPrints[curPos.getX()][curPos.getY()] = true;
}
public static Position nextPos(Position curPos, int di) {
int x = curPos.getX();
int y = curPos.getY();
switch(di) {
case 1: {
y = curPos.getY() + 1; //東
}
break;
case 2: {
x = curPos.getX() + 1; //南
}
break;
case 3: {
y = curPos.getY() - 1; //西
}
break;
case 4: {
x = curPos.getX() - 1; //北
}
break;
}
return new Position(x, y);
}
public static void markPrint(Position seat) {
endPrints[seat.getX()][seat.getY()] = true;
}
}
測試用例:
4 4
1 1 1 1
0 0 0 1
0 0 1 1
9 1 1 1
輸出結(jié)果:
x - y = 1 - 1
x - y = 1 - 2
x - y = 1 - 3
x - y = 1 - 4
x - y = 2 - 4
x - y = 3 - 4
x - y = 4 - 4
x - y = 4 - 3
x - y = 4 - 2
x - y = 4 - 1
總共花費(fèi)了10步, 找到目標(biāo)
true
測試用例:
8 8
1 1 0 0 0 0 1 1
1 1 0 0 0 0 0 0
0 1 1 1 1 0 0 0
1 1 1 1 0 0 0 0
0 1 0 0 1 1 1 1
0 1 1 9 0 0 0 0
0 0 0 0 0 0 0 0
1 0 1 0 1 1 1 1
輸出結(jié)果:
x - y = 1 - 1
x - y = 1 - 2
x - y = 2 - 2
x - y = 3 - 2
x - y = 3 - 3
x - y = 3 - 4
x - y = 3 - 5
x - y = 4 - 4
x - y = 4 - 3
x - y = 4 - 2
x - y = 5 - 2
x - y = 6 - 2
x - y = 6 - 3
x - y = 6 - 4
總共花費(fèi)了14,步, 找到目標(biāo)
true
測試用例:
4 4
1 0 0 1
1 1 1 1
0 0 1 0
1 1 1 1
輸出結(jié)果:
x - y = 1 - 1
x - y = 2 - 1
x - y = 2 - 2
x - y = 2 - 3
x - y = 2 - 4
x - y = 1 - 4
x - y = 3 - 3
x - y = 4 - 3
x - y = 4 - 4
x - y = 4 - 2
x - y = 4 - 1
總共花費(fèi)了12步,沒有找到目標(biāo)
false
三、總結(jié)
兩種方法完成了問題的解決,當(dāng)然,遞歸的方法只是用來擴(kuò)展思路,其實(shí),使用遞歸并且記錄之前已經(jīng)遍歷到一些信息也是可以完成問題的解答,這就涉及到了動態(tài)規(guī)劃。這就交給讀者去完成啦。
好了,謝謝各位觀看,我們下期再會。
總結(jié)
以上是生活随笔為你收集整理的【面试】如何找到迷宫出口的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 战双帕弥什显示服务器满员,战双帕弥什星火
- 下一篇: 战神背光键盘如何关系_技术丨如何解决背光