《剑指Offer》Java刷题 NO.65 矩阵中的路径(数组、DFS、回溯法、是否存在路径)

《剑指Offer》Java刷题 NO.65 矩阵中的路径(数组、DFS、回溯法、是否存在路径)

传送门:《剑指Offer刷题总目录》

时间:2020-07-27
题目:

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如下图 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。


思路:

  • 其实是DFS的思想,对每个点做DFS,只不过DFS是为了寻找所有可能路径,这道题是判断是否存在一条路径,所以只要有一条是符合的就可以直接返回了;
  • 另外在做DFS的时候可以剪枝,只要当前位置的字符和字符串对应位置的字符无法匹配,就返回false,不用再看四个方向了;如果可以匹配,就递归四个方向看,只要任意一个方向可以返回true就说明可以匹配成功
  • 注意返回上一层的时候,也就是回溯的时候,要把当前字符重新标记为未访问,因为只需要保证同一条路径不能经过同一个格子,不同的路径是可以的
    注意: 这个题目里面是用一维数组保存的矩阵

DFS模板

int check(参数)
{
    if(满足条件)
        return 1;
    return 0;
}

void dfs(int step)
{
        标记
        判断边界
        {
            相应操作
        }
        尝试每一种可能
        {
               满足check条件//可以是判断该元素有没有被访问过
               //也可以在这里做标记
               继续下一步dfs(step+1)
               恢复初始状态(回溯的时候要用到)//!!!回溯的时候很重要
        }
} 

Java代码:

/**
 * @author LiMin
 * @Title: HasPath
 * @Description: 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
 * @date 2020/7/28  9:27
 */
public class HasPath {
    public static void main(String[] args) {
        HasPath has = new HasPath();
        char[] matrix = "ABCESFCSADEE".toCharArray();
        char[] str = "ABCCED".toCharArray();
        System.out.println(has.hasPath(matrix, 3, 4, str));
    }

    public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
        if (matrix == null || matrix.length == 0 || matrix.length < str.length || str == null || str.length <= 0) {
            return false;
        }
        
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (dfs(matrix, rows, cols, str, 0, j, i)) {
                    return true;//剪枝
                }
            }
        }
        return false;
    }

    public boolean dfs(char[] matrix, int rows, int cols, char[] str, int step, int x, int y) {
        int index = cols * y + x;//先计算出(x,y)在一维数组中的索引值
        //判断边界和check条件
        if (x < 0 || x >= cols || y < 0 || y >= rows || matrix[index] == '#' || matrix[index] != str[step]) {
            return false;
        }
        if (step == str.length - 1) {
            return true;//匹配成功的截止条件
        }
        //当前字符可以匹配,标记为已访问,这里不用再专门申请一个标记数组了
        char c = matrix[index];
        matrix[index] = '#';
        //递归检查四个方向是否至少有一个可以完全匹配,只要有一个匹配就可以返回了,所以用“或”来连接
        if (dfs(matrix, rows, cols, str, step + 1, x + 1, y) || dfs(matrix, rows, cols, str, step + 1, x - 1, y) 
                || dfs(matrix, rows, cols, str, step + 1, x, y - 1) || dfs(matrix, rows, cols, str,step + 1, x, y + 1)) {
            return true;//剪枝
        }
        //回溯:当前字符在当前路径的step不匹配,但是之后可以出现在其他路径,所以应该重新标记为未访问;另外step因为递归调用被压栈,返回上一层可以自动减一
        matrix[index] = c;
        //走到这还没返回说明走不通
        return false;
    }
}
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页