【剑指offer】12. 矩阵中的路径

165 阅读3分钟

题目描述

在这里插入图片描述

在这里插入图片描述

// 12. 矩阵中的路径

// 力扣
// 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某
// 字符串所有字符的路径。路径可以从矩阵中的任意一格开始,
// 每一步可以在矩阵中向左、右、上、下移动一格。如果一条路
// 径经过了矩阵的某一格,那么该路径不能再次进入该格子。例
// 如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径
// 中的字母用加粗标出)。
// [["a","b","c","e"],
// ["s","f","c","s"],
// ["a","d","e","e"]]

// 但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占
// 据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。


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

题解

/////////////////////////////////////// 回溯搜索法 ///////////////////////////////////////
构建待搜索矩阵同尺寸的布尔矩阵marked,用于标记该位置元素是否被使用过。
设置路径步长pathLen,用于同步搜索目标的长度。
遍历待搜索矩阵matrix每一个位置的元素,对该位置的元素做所有方向的搜索,搜索不到就回溯到原状态,之前修改的marked和pathLen要重置。

// 牛客

// 运行时间 12ms
// 占用内存 9592KB
public class Solution {
    
    private final static int[][] next = {{0,-1}, {0,1}, {-1,0}, {1,0}}; // 左右上下四个方向
    private int rows;
    private int cols;
    
    // 解题函数
    public boolean hasPath(char[] array, int rows, int cols, char[] str) {
        if (rows == 0 || cols == 0)
            return false;
        this.rows = rows;
        this.cols = cols;
        boolean[][] marked = new boolean[rows][cols];  // 标记状态矩阵,可标记某元素是否被使用,回溯后使用状态被清空
        char[][] matrix = buildMatrix(array);  // 题目给的数组char[]转化为矩阵char[][]
        // 两层for循环,遍历待搜索矩阵matrix的所有元素,第r行第c列元素为matrix[c][r]
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                if (backTracking(matrix, str, marked, r, c, 0)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    // 回溯搜索法
    // 输入变量:待搜索矩阵matrix,搜索目标str,状态标记矩阵marked(初始化为全false), 遍历行r,遍历列c,已遍历的路径步长pathLen(初始化为0)
    // 每一次backTracking搜索,路径长度pathLen将+1,搜索失败,则回溯进行下一次for遍历
    // pathLen又会重置为0,marked也会重置为全false。
    private boolean backTracking(char[][] matrix, char[] str, boolean[][] marked, int r, int c, int pathLen) {
        if (pathLen == str.length)  // 如果遍历路径步长等于搜索目标str的长度,返回true
            return true;
        if (r < 0 || r >= rows || c < 0 || c >= cols)  // 如果遍历行和列超出边界,返回false,(回到上一次marked的标记和路径步数pathLen,即进行了回溯)
            return false;
        if (marked[r][c])  // 如果遍历元素被使用过,返回false,进行回溯
            return false;
        if (matrix[r][c] != str[pathLen])  // 如果搜索矩阵遍历元素与当前路径步数对应的搜索目标字符不相等,返回false,进行回溯
            return false;                  // 换言之,不返回false,说明遍历元素与对应目标字符是一致的。
        
        marked[r][c] = true;  // 当前元素标记为已被使用
        // 开始以当前遍历元素matrix[r][c]为起点进行搜索,for循环取next中左右上下四个方向,递归backTracking进行搜索
        // 路径pathLen+1
        for (int[] dic : next) {  
            if (backTracking(matrix, str, marked, r + dic[0], c + dic[1], pathLen + 1)) {
                return true;
            }
        }
        // 当前遍历元素搜索结束,未发现目标,元素标记重置回false
        marked[r][c] = false;
        return false;  // 搜索结束,返回false。进行回溯
    }
    
    // 将数组char[]转为矩阵char[][]
    public char[][] buildMatrix(char[] array) {
        char[][] matrix = new char[rows][cols];
        int idx = 0;
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                matrix[r][c] = array[idx++];
            }
        }
        return matrix;
    }
}
// 力扣

// 和牛客原理是一样的
// 执行用时:7 ms, 在所有 Java 提交中击败了40.96%的用户
// 内存消耗:40.1 MB, 在所有 Java 提交中击败了87.40%的用户
class Solution {
    private int rows;
    private int cols;
    private final int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};  // 左右上下

    public boolean exist(char[][] board, String word) {
        this.rows = board.length;
        this.cols = board[0].length;

        char[] wordarray = word.toCharArray();
        if (rows == 0 || cols == 0)
            return false;
        boolean[][] marked = new boolean[rows][cols];
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                if (backTracking(board, wordarray, marked, r, c, 0)) {
                    return true;
                }
            }
        }
        return false;
    }

    public boolean backTracking(char[][] matrix, char[] str, boolean[][] marked, int r, int c, int pathLen) {
        if (pathLen == str.length)
            return true;
        if (r < 0 || r >= rows || c < 0 || c >= cols)
            return false;
        if (marked[r][c])
            return false;
        if (matrix[r][c] != str[pathLen])
            return false;
        
        marked[r][c] = true;
        for (int[] dic : next) {
            if (backTracking(matrix, str, marked, r + dic[0], c + dic[1], pathLen + 1)) 
                return true;
        }
        marked[r][c] = false;
        return false;
    }
}