难度等级:中等
上一篇算法:
力扣此题地址:
1.题目:矩阵中的路径
给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
例如,在下面的 3×4 的矩阵中包含单词 "ABCCED"(单词中的字母已标出)。
示例 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
2.解题思路:
回溯法(用递归):
1.先在矩阵中逐个元素遍历找出要查找字符串的第一个字符的元素的位置
2.从那个元素位置开始进行上左下右的匹配
(1)如果匹配成功就进入字符串的下一个字符的匹配,同时标记此元素为#,防止再次匹配到这个元素
(2)如果匹配不成功,则退回上一个匹配成功的位置重新进行查找,也就是换一条路径。
3.重复上述步骤2的操作,用递归的方式,直到找到最后一个字符串元素,返回true,否则返回false。
具体的操作如下:
本题提供了一个矩阵,矩阵是一个二维数组,需要我们在二维数组中进行搜索,为了能够覆盖所有的情况,必然要使用两个嵌套的循环。
在搜索过程中,当遇到匹配成功的元素,搜索其下一元素的操作与当前的操作一致,即可以使用递归。
- 递归参数: 当前元素在矩阵
board
中的行列索引i
和j
,当前目标字符在word
中的索引k
。终止条件:
- 返回 false:
(1) 行或列索引越界
(2) 当前矩阵元素与目标字符不同
(3) 当前矩阵元素已访问过
- 返回 true:
k = len(word) - 1
,即字符串word
已全部匹配。- 递推工作:
- 标记当前矩阵元素: 将
board[ i ] [ j ]
修改为特殊字符 # ,代表此元素已访问过,防止之后搜索时重复访问。- 搜索下一节点: 朝当前元素的 上、左、下、右 四个方向开启下层递归。
- 回退时还原当前矩阵元素: 将
board[ i ] [ j ]
元素还原至初始值,即 word[k] 。- 返回值: 返回布尔量
res
,代表是否搜索到目标字符串。
3.代码实现:
class Solution {
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[0].length; j++) {
// 以该元素为起始点,递归检查是否符合要求
if(dfs(board, words, i, j, 0)) return true;
}
}
return false;
}
boolean dfs(char[][] board, char[] word, int i, int j, int k) {
// 边界情况判断
// 行越界
// 列越界
// 矩阵元素已访问过
if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
// 之前已经和目标字符串匹配成功了 length - 1 个字符,此时又匹配成功了最后一个元素,直接返回结果
if(k == word.length - 1) return true;
// 标记当前矩阵元素,将其修改为特殊字符 # ,代表此元素已访问过,防止之后搜索时重复访问。
board[i][j] = '#';
// 检查元素的四个方向 上 左 下 右
boolean res = dfs( board , word , i , j - 1 , k + 1 )
|| dfs( board , word , i - 1 , j , k + 1 )
|| dfs( board , word , i , j + 1 , k + 1 )
|| dfs( board , word , i + 1 , j , k + 1 );
board[i][j] = word[k];
return res;
}
}
参考: