剑指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个方向,但是其中一个方向是已经访问过的上一个元素的位置,不会进入递归),走
步,就一共有
种路径数。
是主函数中的双层循环。
空间复杂度:,递归深度不超过
。最坏的情况,
,这时的输入路径需要遍历矩阵中所有元素才能得到,空间复杂度为
。