矩阵中的路径|刷题打卡

224 阅读2分钟

掘金团队号上线,助你 Offer 临门! 点击 查看详情

一、题目描述

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

[["a","b","c","e"],
["s","f","c","s"],
["a","d","e","e"]]

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

示例 1:

输入

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"

输出

true

示例 2:

输入

board = [["a","b"],["c","d"]], word = "abcd"

输出

false

提示

1 <= board.length <= 200
1 <= board[i].length <= 200

二、思路分析

我的思路

  1. 没想出来,其实也是因为多虑了,题目也没有描述清楚,看题解大部分都是路径是连续的,没有说路径不连续的情况
  2. 这题目给的题解和我对题目意思的理解难度差了很多(题目只是说了包含,没有说顺序及连续性)。

最佳思路

  • DFS+回溯法
  • 我们先开始遍历这个二维数组,当发现第一个数字和给定word第一个字符匹配的时候,开始进入深度优先遍历dfs。
    • 深度遍历就是往上下左右四个方向探路,如果已经走过的路以及数组的边界,那么就返回false表明路走不通。只要能走通就可以一直递归下去,知道word全部被匹配完。
  • 如果出现了 比如要ABCD 结果 矩阵中有路线 ABCC ABCD 到B的时候有2个C(当然可以是多个)。那么先走了CC的那个会不断的返回false,到了B这一级,B会继续换条路往下走。

三、AC 代码

最佳写法:

public boolean exist(char[][] board, String word) {
    char[] words = word.toCharArray();
    // 遍历这个数组去匹配第一个字符
    for (int i = 0; i < board.length; i++) {
        for (int j = 0; j < board[i].length; j++) {
            if (dfs(board, words, i, j, 0)) {
                // 如果dfs发现了路径就返回
                return true;
            }
        }
    }
    return false;
}
/**
 * 主要就是对比word[k]和二维数组中的元素做比较,如果相同就往下一个,如果不同就返回false
 *
 * @param board 二维数组
 * @param word  需要找到的路径
 * @param i     当前二维数组走到的位置的i值
 * @param j     当前二维数组走到的位置的j值
 * @param k     word已经遍历到的位置
 */
public boolean dfs(char[][] board, char[] word, int i, int j, int k) {
    // 如果触碰到了边界 || 当前字符和需要的字符不匹配的话,说明这条路走不通
    if (i >= board.length || i < 0 || j >= board[0].length || j < 0 ||
        return false;
    }
    // *** 核心 *** 递归弹出的条件,words最后一个字符匹配也找到了
    if (k == word.length - 1) {
        return true;
    }
    // 因为遍历后的节点是不能再走的,所以将其设置为'\0',这样永远无法匹配就等于不会走这条路。
    // 注意一点:当前遍历是认为这条路走得通的,但是最后发现走不通了,回来的时候还需要将这个数改回去。
    board[i][j] = '\0';
    // **** 核心的核心 ****
    // 这是递归的关键,就是如果发现当前字符是匹配的,那么就递归他的上下左右方向。
    if (dfs(board, word, i + 1, j, k + 1) || // 向右
            dfs(board, word, i - 1, j, k + 1) || // 向做
            dfs(board, word, i, j + 1, k + 1) || // 向下
            dfs(board, word, i, j - 1, k + 1)) { // 向上
        return true;
    }
    // 如果走了发现最红没走通,将数值改回去
    board[i][j] = word[k];
    return false;
}

四、总结

这种题解前提就是路径是连续的。如果不连续的话,走到断了的地方就全部返回false了。