【面试】如何找到迷宫出口

简介: 1 1 1 10 0 0 11 9 0 01 1 1 1其中1代表此位置是可以通过的,0代表此位置是不可通过的,要从起点开始,确定是否存在这样一条路径,可以从起点找到数字9。也就是找到这样一条路径1->1->1 ...... ->9。这个问题是寻找迷宫出口的变形。可以将9看成是迷宫的出口,而给出的开始位置是迷宫的入口,寻找一条路径。

一、问题描述


给出如下的矩阵


1 1 1 1

0 0 0 1

1 9 0 0

1 1 1 1


其中1代表此位置是可以通过的,0代表此位置是不可通过的,要从起点开始,确定是否存在这样一条路径,可以从起点找到数字9。也就是找到这样一条路径1->1->1 ...... ->9。这个问题是寻找迷宫出口的变形。可以将9看成是迷宫的出口,而给出的开始位置是迷宫的入口,寻找一条路径。


二、问题求解


当矩阵阶数不是太大的时,可以使用递归来求解,但是,当矩阵的阶数变得很大时,则需要使用另外的方法进行计算,也就是采用栈来进行求解。

下面是两种解决方法

1.当矩阵阶数较小时,采用递归进行求解,这种方式只是用来开拓思路,解此问题存在一定的局限性。

源代码如下:


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++) {   //初始化数组元素
            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; //入口横坐标
        int startY = 1; //入口纵坐标
        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

输出结果为:true

测试用例:

4 4

1 1 1 1

0 0 0 1

0 0 1 1

9 1 1 1

输出结果:java.lang.StackOverflowError,堆栈溢出

 

2.使用递归的方法要选择好测试用例,很可能因为测试用例的选取不恰当而造成堆栈溢出。递归只是为了开拓思路而已,下面使用栈结构来解决堆栈溢出的问题。

源代码如下:


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;    //对应的值
    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> {//定义栈结构
    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++) {    //初始化数组元素
            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;    //入口横坐标
        int startY = 1;    //入口纵坐标
        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>();
        //当前的位置
        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) {//如果已经找到目标,则返回
                    System.out.println("总共花费了" + curStep + "步, 找到目标");
                    return true;
                }
                curPos = nextPos(curPos, 1);//试探下一步,即东边的,但是不放入栈中
                curStep++;//步数加1
            } else {//改位置不可通过
                if(!stack.isEmpty()) {//栈不为空
                    Item item = stack.pop();//出栈
                    while(item.getDi() == 4 && !stack.isEmpty()) {//留下了脚印的个数加上不可通过的个数之和为4,进行出栈处理
                        markPrint(item.getSeat());//留下不可通过印记并进行出栈处理
                        item = stack.pop();//出栈
                    }
                    if(item.getDi() < 4) {//四个方向还未试探完
                        item.setDi(item.getDi() + 1);//换下一个方向进行试探
                        stack.push(item);//入栈
                        curPos = nextPos(item.getSeat(), item.getDi());//试探下一个位置
                    }
                }
            }
        } while(!stack.isEmpty());   
        System.out.println("总共花费了" + curStep + "步,没有找到目标");
        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


输出结果:


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


总共花费了10步, 找到目标

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

输出结果:


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


总共花费了14,步, 找到目标

true


测试用例:


4 4

1 0 0 1

1 1 1 1

0 0 1 0

1 1 1 1


输出结果:


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

总共花费了12步,没有找到目标

false

 

三、总结


  两种方法完成了问题的解决,当然,递归的方法只是用来扩展思路,其实,使用递归并且记录之前已经遍历到一些信息也是可以完成问题的解答,这就涉及到了动态规划。这就交给读者去完成啦。

  好了,谢谢各位观看,我们下期再会。

目录
相关文章
|
6月前
|
Java
P9242 [蓝桥杯 2023 省 B] 接龙数列JAVA,边权为1的最短路问题,洛谷P9242 [蓝桥杯 2023 省 B] 接龙数列​编辑力扣1926.迷宫离入口最近的出口力扣433.
P9242 [蓝桥杯 2023 省 B] 接龙数列JAVA,边权为1的最短路问题,洛谷P9242 [蓝桥杯 2023 省 B] 接龙数列​编辑力扣1926.迷宫离入口最近的出口力扣433.
|
7月前
【错题集-编程题】孩子们的游戏(圆圈中最后剩下的数)(约瑟夫环)
【错题集-编程题】孩子们的游戏(圆圈中最后剩下的数)(约瑟夫环)
【每日一道智力题】之如何最快的找到最轻的砝码
【每日一道智力题】之如何最快的找到最轻的砝码
211 0
|
C语言 C++
信奥赛一本通2038:【例5.5】最大数位置
【题目描述】 输入n个整数,存放在数组a[1]至a[n]中,输出最大数所在位置(n≤1000)。 【输入】 第一行,数的个数n; 第二行,n个正整数,每个数在232−1之内。 【输出】 最大数所在位置。 【输入样例】 5 67 43 90 78 32
431 0
|
算法
蛮力法解决旅行商问题(穷举查找求最短路径)含解析与代码实现
蛮力法解决旅行商问题(穷举查找求最短路径)含解析与代码实现
432 0
|
机器学习/深度学习 算法
LeetCode每日一题——882. 细分图中的可到达节点
给你一个无向图(原始图),图中有 n 个节点,编号从 0 到 n - 1 。你决定将图中的每条边 细分 为一条节点链,每条边之间的新节点数各不相同。
96 0
LeetCode每日一题——882. 细分图中的可到达节点
最少转机(无路径之和) 图的广度优先遍历
最少转机(无路径之和) 图的广度优先遍历
最少转机(无路径之和) 图的广度优先遍历
|
存储 算法 索引
面试官问我有环链表中怎么找到入口,本以为很简单当场却想傻了
链表是否有环问题看似简单,但实际处理上有很多需要注意的,这个问题是非常高频笔试面试题,记忆不牢固容易遗忘,可以认真看看学习一波!有个小伙伴就在某手面试中遇到了。
117 0
面试官问我有环链表中怎么找到入口,本以为很简单当场却想傻了
|
人工智能 算法 定位技术
【算法作业】实验五:神奇宝贝大军 & 到迷宫出口的最短路径
【算法作业】实验五:神奇宝贝大军 & 到迷宫出口的最短路径
274 0
【算法作业】实验五:神奇宝贝大军 & 到迷宫出口的最短路径
百度面试题——迷宫问题(超详细解析)
百度面试题——迷宫问题(超详细解析)
203 0
百度面试题——迷宫问题(超详细解析)