给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。若是 word 存在于网格中,返回 true ;不然,返回 false 。javascript
单词必须按照字母顺序,经过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不容许被重复使用。java
提示:markdown
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board 和 word 仅由大小写英文字母组成
复制代码
回溯法(backtracking)是优先搜索的一种特殊状况,又称为试探法,经常使用于须要记录节点状态的深度优先搜索。一般来讲,排列、组合、选择类问题使用回溯法比较方便。 顾名思义,回溯法的核心是回溯。在搜索到某一节点的时候,若是咱们发现目前的节点(及其子节点)并非需求目标时,咱们回退到原来的节点继续搜索,而且把在目前节点修改的状态 还原。函数
这样的好处是咱们能够始终只对图的总状态进行修改,而非每次遍历时新建一个图来储存 状态。 在具体的写法上,它与普通的深度优先搜索同样,都有 [修改当前节点状态]→[递归子节 点] 的步骤,只是多了回溯的步骤,变成了 [修改当前节点状态]→[递归子节点]→[回改当前节点 状态]。 回溯法。有两个小诀窍,一是按引用传状态,二是全部的状态修 改在递归完成后回改。 回溯法修改通常有两种状况,一种是修改最后一位输出,好比排列组合;一种是修改访问标 记,好比矩阵里搜字符串。ui
不一样于排列组合修改输出方式,而是修改访问标记。spa
在咱们对任意位置进行深度优先搜索时,咱们先标记当前位置为已访问,以免重复遍历(如防止向右搜索后 又向左返回);code
在全部的可能都搜索完成后,再回改当前位置为未访问,防止干扰其它位置搜索 到当前位置。orm
使用回溯法,咱们能够只对一个二维的访问矩阵进行修改,而不用把每次的搜索状 态做为一个新对象传入递归函数中。对象
/** * @param {character[][]} board * @param {string} word * @return {boolean} */
const direction = [-1, 0, 1, 0, -1];
const exist = function(board, word) {
if(!board.length) return false;
let m = board.length, n = board[0].length;
let visited = Array.from({length: m}, ()=> Array(n).fill(false));
const find = {flag:false};
for(let i = 0; i < m; i++) {
for(let j = 0; j < n; j++) {
backtracking(i, j, board, word, find, visited, 0);
}
}
return find.flag;
};
const backtracking = function(i, j, board, word, find,visited, pos) {
if(i < 0 || i >= board.length || j < 0 || j >= board[0].length) {
return;
}
if(visited[i][j] || (board[i][j] !== word[pos]) || find.flag) {
return;
}
if(pos === word.length - 1) {
find.flag = true
return;
}
visited[i][j] = true; // 修改当前节点状态。
for(let k = 0; k < 4; k++){
const dx = i + direction[k];
const dy = j + direction[k+1];
backtracking(dx, dy, board, word,find, visited, pos + 1);
}
visited[i][j] = false; // 恢复节点状态;
}
复制代码