「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」。
题目
链接:leetcode-cn.com/problems/wo…
给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
**输入:**board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" **输出:**true
示例 2:
**输入:**board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE" **输出:**true
示例 3:
**输入:**board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB" **输出:**false
提示:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board
和word
仅由大小写英文字母组成
**进阶:**你可以使用搜索剪枝的技术来优化解决方案,使其在 board
更大的情况下可以更快解决问题?
解题思路
思路1
回溯算法
(深度优先搜索)
- 遍历矩阵
board
在每次遍历以当前元素为起点进行深度优先搜索 - 分别遍历上下左右四个方向,匹配到
word
即返回true
关键
- 深度优先继续条件:
- 当前元素不超过矩阵边界:
newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length
- 当前元素在此次搜索中没有访问过: 维护矩阵
visited
记录元素是否访问过
- 当前元素不超过矩阵边界:
- 深度优先结束标志:
- 当前元素不等于要匹配的字符 -> 返回
false
- 否则,如果当前访问过的字符串长度已经等于
word
长度 -> 返回true
- 当前元素不等于要匹配的字符 -> 返回
代码
var exist = function(board, word) {
const visited = new Array(board.length);
for (let i = 0; i < board.length; i++) {
visited[i] = new Array(board[0].length).fill(false);
}
for (let i = 0; i < board.length; i++) {
for (let j = 0; j < board[0].length; j++) {
if (dfs(board, word, visited, i, j, 0)) return true;
}
}
return false;
};
const dfs = (board, word, visited, i, j, k) => {
// ! locate element in char array
if (board[i][j] !== word.charAt(k)) return false;
else if (k === word.length - 1) return true;
visited[i][j] = true;
const directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
let res = false;
for (const [dx, dy] of directions) {
const newi = i + dx, newj = j + dy;
if (newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length) {
if (!visited[newi][newj]) {
if (dfs(board, word, visited, newi, newj, k + 1)) {
res = true;
break;
}
}
}
}
visited[i][j] = false;
return res;
}
思路2
- 首先遍历
board
,从每一个位置开始使用回溯,如果从当前位置出发找到了找到了就结束返回true
,当前位置没有找到就下一个,如果都没有找到就返回false. - 递归方法,我是按照上右下左的顺序开始的,大家可以自定义,结束条件是
index
值等于word.length-1
,表示前面的全部匹配上了。 - 注意每一次查找都需要判断是否全部匹配,如果全部匹配可以直接返回,如果不匹配再接着上右下左这个顺序查找。
代码
/**
* @param {character[][]} board
* @param {string} word
* @return {boolean}
*/
var exist = function(board, word) {
var m = board.length
var n = board[0].length
//初始化一个访问数组,visited,false;
let visited = new Array(m).fill(false).map(() => new Array(n).fill(false));
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
//0表示匹配word字符的位置;
let flag = huis(i, j, word, 0);
if (flag) {
return flag;
}
}
}
function huis(i, j, word, index) {
// 按照上右下左的顺序来查询字符串
if (i >= 0 && i <= m - 1 && j >= 0 && j <= n - 1 && board[i][j] == word[index] && visited[i][j] == false) {
if (index == word.length - 1) {
return true;
}
let flag = false;
visited[i][j] = true;
flag = huis(i - 1, j, word, index + 1);
if (flag) {
return flag;
}
flag = huis(i, j + 1, word, index + 1);
if (flag) {
return flag;
}
flag = huis(i + 1, j, word, index + 1);
if (flag) {
return flag;
}
flag = huis(i, j - 1, word, index + 1);
if (flag) {
return flag;
}
visited[i][j] = false;
return false;
} else {
return false;
}
}
return false;
};