剑指Offer刷题记录,第八题。

剑指 Offer 12. 矩阵中的路径(medium)


方法一:递归 + 回溯 + 剪枝

思路:本题提供了一个矩阵,矩阵是一个二维数组,需要我们在二维数组中进行搜索,为了能够覆盖所有的情况,必然要使用两个嵌套for循环
在搜索过程中,当遇到匹配成功的元素,搜索其下一元素的操作与当前的操作一致,即可以使用递归
递归参数:
当前元素在矩阵 board 中的行列索引 i 和 j ,当前目标字符在word 中的索引 idx 。
终止条件:
返回 false:
(1) 行或列索引越界

(2) 当前矩阵元素与目标字符不同

(3) 当前矩阵元素已访问过

返回 true: idx == len(word) - 1 ,即字符串 word 已全部匹配。

递推工作:
标记当前矩阵元素: 将 board[ i ] [ j ] 修改为特殊字符 '\0',代表此元素已访问过,防止之后搜索时重复访问。
搜索下一节点: 朝当前元素的 四个方向开启下层递归。
回退时还原当前矩阵元素: 将 board[ i ] [ j ] 元素还原至初始值,即 word[idx] 。
返回值: 返回布尔量 res ,代表是否搜索到目标字符串。

class Solution {
   
    public boolean exist(char[][] board, String word) {
   
        // 先将字符串进行拆分,一个一个元素进行匹配
        char[] words = word.toCharArray();
        // 通过两层嵌套for,覆盖所有的情况
        for (int i = 0; i < board.length; i++) {
   
            for (int j = 0; j < board[0].length; j++) {
   
                // 以该元素为起始点,递归检查是否符合要求
                if (helper(i, j, 0, board, words)) return true;
            }
        }
        // 检查所有的矩阵元素,都没有匹配上的,返回false。
        return false;
    }
    boolean helper(int i, int j, int idx, char[][] board, char[] word) {
   
        // 边界条件(1)行越界(2)列越界(3)矩阵元素已经被访问过
        if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] != word[idx]) {
   
            return false;
        }
        // 成功匹配目标字符串,返回true
        if (idx == word.length - 1) {
   
            return true;
        }
        // 将当前矩阵元素进行标记,代表已经访问过,防止后续递归重复访问。
        
        board[i][j] = '\0';
        // 搜索元素的四个方向,下,上,右,左,匹配下一个目标元素
        boolean res = helper(i + 1, j, idx + 1, board, word) 
                || helper(i - 1, j, idx + 1, board, word) 
                || helper(i, j + 1, idx + 1, board, word) 
                || helper(i, j - 1, idx + 1, board, word);
        // 回溯,恢复当前矩阵元素。
        board[i][j] = word[idx];
        
        // 返回结果
        return res;
    }
}

时间复杂度: O(3KMN), 最差情况下,需要遍历矩阵中长度为K字符串的所有方案,时间复杂度为O(3K);矩阵***有MN个起点,时间复杂度为O(MN),因此,总的时间复杂度为O(3KMN)。(方案数计算:设字符串长度为K,搜索中每个字符有上、下、左、右四个方向可以选择,舍弃回头(上个字符)的方向,剩下三种选择,因此方案数的复杂度为O(3K)。)
空间复杂度: O(K), 搜索过程中的递归深度不超过K,因此系统因函数调用累计使用的栈空间占用O(K)。最坏情况下K = MN, 递归深度为MN,此时系统栈调用O(MN)的额外空间。

总结:就差一点就写出来了,没想到双重for循环以及回溯,这类题还需要提高敏感性。
参考阅读:

  1. 最优解.
  2. 图解.
全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务