数据保证有唯一解,可以考虑BFS、DFS两种遍历方式

广度优先搜索(BFS)

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

/**
 * 【迷宫问题】  -  广度优先搜索(BFS)
 *
 *  定义一个二维数组 N*M ,如 5 × 5 数组下所示:
 *      int maze[5][5] = {
 *      0, 1, 0, 0, 0,
 *      0, 1, 1, 1, 0,
 *      0, 0, 0, 0, 0,
 *      0, 1, 1, 1, 0,
 *      0, 0, 0, 1, 0,
 *     };
 *
 *    它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,
 *    只能横着走或竖着走,不能斜着走,
 *    要求编程序找出从左上角到右下角的路线。
 *    入口点为[0,0],既第一格是可以走的路。
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int rows = sc.nextInt();
        int columns = sc.nextInt();
        // 构建迷宫
        int[][] ints = new int[rows][columns];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                ints[i][j] = sc.nextInt();
            }
        }


        // 创建队列以及初始化
        ArrayDeque<Node> arrayDeque = new ArrayDeque<>();
        arrayDeque.addLast(new Node(0, 0, null));
        // 已经检验过节点列表
        ArrayList<String> checkedNodeList = new ArrayList<>();

      	// 终点节点
        Node endNode = null;
        while (!arrayDeque.isEmpty()) {
            // 弹出节点
            Node headNode = arrayDeque.pollFirst();
            // 判断是否抵达终点
            if ((headNode.x == rows - 1) && (headNode.y == columns - 1)) {
                endNode = headNode;
                break;
            }

            // 横坐标与纵坐标
            int horizontal = headNode.x;
            int vertical = headNode.y;
            // 校验是否已检查
            if (checkedNodeList.contains("" + horizontal + vertical)) {
                continue;
            }

            // 该节点不是终点,则获取该节点所有【值为0】的邻居节点,按照【上下左右】的顺序插入队列
            if (horizontal != 0 && ints[horizontal - 1][vertical] == 0) {
                arrayDeque.addLast(new Node(horizontal - 1, vertical, headNode)); // 上节点
            }

            if (horizontal != rows - 1 && ints[horizontal + 1][vertical] == 0) {
                arrayDeque.addLast(new Node(horizontal + 1, vertical, headNode)); // 下节点
            }

            if (vertical != 0 && ints[horizontal][vertical - 1] == 0) {
                arrayDeque.addLast(new Node(horizontal, vertical - 1, headNode)); // 左节点
            }

            if (vertical != columns - 1 && ints[horizontal][vertical + 1] == 0) {
                arrayDeque.addFirst(new Node(horizontal, vertical + 1, headNode)); // 右节点
            }
            // 添加至已校验列表
            checkedNodeList.add("" + horizontal + vertical);
        }
		
      	// 利用栈的特性,从起点位置开始打印
        Stack<String> stack = new Stack<>();
        while (endNode != null) {
            stack.push("(" + endNode.x + "," + endNode.y + ")");
            endNode = endNode.father;
        }
        // 打印路径
        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}

class Node {
    int x;
    int y;
    Node father;

    public Node(int x, int y, Node node) {
        this.x = x;
        this.y = y;
        this.father = node;
    }
}

深度优先搜索(DFS)

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

/**
 * 【迷宫问题】  -  深度优先搜索(DFS)
 *
 *  定义一个二维数组 N*M ,如 5 × 5 数组下所示:
 *      int maze[5][5] = {
 *      0, 1, 0, 0, 0,
 *      0, 1, 1, 1, 0,
 *      0, 0, 0, 0, 0,
 *      0, 1, 1, 1, 0,
 *      0, 0, 0, 1, 0,
 *     };
 *
 *    它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,
 *    只能横着走或竖着走,不能斜着走,
 *    要求编程序找出从左上角到右下角的路线。
 *    入口点为[0,0],既第一格是可以走的路。
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int rows = sc.nextInt();
        int columns = sc.nextInt();
        // 构建迷宫
        int[][] ints = new int[rows][columns];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                ints[i][j] = sc.nextInt();
            }
        }

        // 创建栈
        Stack<Point> stack = new Stack<>();
        // 创建已检验节点列表
        ArrayList<String> checkedPointList = new ArrayList<>();

        // 起始节点入栈
        stack.push(new Point(0, 0, null));
        // 起始节点已检查
        checkedPointList.add("" + 0 + 0);

        Point endPoint = dfs(ints, stack, checkedPointList);

		// 利用栈的特性,从起点位置开始打印
        Stack<String> printStack = new Stack<>();
        while (endPoint != null) {
            printStack.push("(" + endPoint.x + "," + endPoint.y + ")");
            endPoint = endPoint.father;
        }
        // 打印路径
        while (!printStack.isEmpty()) {
            System.out.println(printStack.pop());
        }
    }

    /**
     * 深度遍历
     *
     * @param ints
     * @param stack
     * @param checkedPointList
     */
    public static Point dfs(int[][] ints, Stack<Point> stack, ArrayList<String> checkedPointList) {
        // 获取头节点
        Point headPoint = stack.peek();
        // 横坐标与纵坐标
        int horizontal = headPoint.x;
        int vertical = headPoint.y;

        // 判断是否抵达终点
        if ((horizontal == ints.length - 1) && (vertical == ints[0].length - 1)) {
            return headPoint;
        }

        // 上节点
        else if (horizontal != 0 && ints[horizontal - 1][vertical] == 0
                            && !checkedPointList.contains("" + (horizontal - 1) + vertical)) {
            stack.push(new Point(horizontal - 1, vertical, headPoint));
            checkedPointList.add("" + (horizontal - 1) + vertical);
            return dfs(ints, stack, checkedPointList);
        }
        // 下节点
        else if (horizontal != ints.length - 1 && ints[horizontal + 1][vertical] == 0
                                          && !checkedPointList.contains("" + (horizontal + 1) + vertical)) {
            stack.push(new Point(horizontal + 1, vertical, headPoint));
            checkedPointList.add("" + (horizontal + 1) + vertical);
            return dfs(ints, stack, checkedPointList);
        }
        // 左节点
        else if (vertical != 0 && ints[horizontal][vertical - 1] == 0
                          && !checkedPointList.contains("" + horizontal + (vertical - 1))) {
            stack.push(new Point(horizontal, vertical - 1, headPoint));
            checkedPointList.add("" + horizontal + (vertical - 1));
            return dfs(ints, stack, checkedPointList);
        }
        // 右节点
        else if (vertical != ints[0].length - 1 && ints[horizontal][vertical + 1] == 0
                                           && !checkedPointList.contains("" + horizontal + (vertical + 1))) {
            stack.push(new Point(horizontal, vertical + 1, headPoint));
            checkedPointList.add("" + horizontal + (vertical + 1));
            return dfs(ints, stack, checkedPointList);
        } else {
            // 死胡同,则回溯至上一个节点
            stack.pop();
            return dfs(ints, stack, checkedPointList);
        }
    }
}

class Point {
    int x;
    int y;
    Point father;

    public Point(int x, int y, Point point) {
        this.x = x;
        this.y = y;
        this.father = point;
    }
}