剑指Offer_#12_矩阵中的路径

剑指Offer_#12_矩阵中的路径

Contents

题目


解答

方法1:回溯法

  • 为什么要用回溯? 回溯问题都是一棵决策树上边的路径选择问题,在决策树的每一层,只能选择其中一个节点,在本题中,“但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。” 这句话告诉我们需要使用回溯法,对进入过的格子做标记。
  • 回溯体现在递归调用之前,进行选择,递归调用之后,撤销选择。具体来说就是体现在代码中的标记格子,还原格子的两行代码,如果没有这两行代码,就会导致重复进入已经进入的格子。
  • 这种“选择”和“撤销选择”的操作是因题目而不同的,如果题目要求的返回值就是给出一个决策树的路径,那么这个“选择”动作应该是向res当中增加一个节点的值,“撤销选择”过程应该是删除最后一个节点的值。本题中的方法比较特殊,就是对矩阵元素进行修改,最后再还原。
class Solution {
    public boolean exist(char[][] board, String word) {
        for(int i = 0; i <= board.length - 1; i++){
            for(int j = 0; j <= board[0].length - 1; j++){
                if(dfs(i, j, board, word, 0)) return true;
            }
        }
        return false;
    }

    private boolean dfs(int i, int j, char[][] board, String word, int index){
        //出口条件
        //下标越界
        if(i < 0 || i >= board.length || j < 0 || j >= board[0].length) return false;
        //字符不符合
        if(board[i][j] != word.charAt(index)) return false;
        //如果最后index大小是word.length() - 1,那么说明所有字符都匹配上了
        if(index == word.length() - 1) return true;
        //选择完一个元素,需要对其进行标记,防止再次进入
        board[i][j] = '0';
        //递推过程:向4个方向遍历,只要其中一个方向是走得通的,就是正确的
        boolean res =   dfs(i + 1, j, board, word, index + 1) ||
                        dfs(i - 1, j, board, word, index + 1) ||
                        dfs(i, j + 1, board, word, index + 1) ||
                        dfs(i, j - 1, board, word, index + 1);
        //撤销选择:无论这条路有没有走通,都要恢复原样,这样才能继续遍历其他的可能路径
        board[i][j] = word.charAt(index);  
        return res;      
    }
}

复杂度分析

时间复杂度:,是字符串长度,表示的是每一步有3个选择(上下左右共4个方向,但是其中一个方向是已经访问过的上一个元素的位置,不会进入递归),走步,就一共有种路径数。是主函数中的双层循环。
空间复杂度:,递归深度不超过。最坏的情况,,这时的输入路径需要遍历矩阵中所有元素才能得到,空间复杂度为

posted @ 2021-05-14 22:09  Howfar's  阅读(52)  评论(0编辑  收藏  举报