function exist(board, word) {
let n = board.length;
let m = board[0].length;
//为节省时间,先排除永不会存在的情况即字符串长度多余二维数组中字符个数
if (word.length > (n * m)) {
return false;
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < m; j++) {
//这里是深搜入口,为节省时间,先判断二维数组中的该位置上的字符是否和字符串的第一个字符相等,相等再进行深搜
if (board[i][j] === word[0]) {
if (dfs(i, j, 0)) {
return true;
}
}
}
}
return false;
function dfs(x, y, k) {
//越界及该位置的字符与字符串中的字符不匹配的情况
if (x >= n || y >= m || x < 0 || y < 0 || board[x][y] !== word[k]) {
return false;
}
//走到这步,也就是对应位置的字符匹配,此时判断是否已经找到字符串的最后一个字符,是则存在
if (k === word.length - 1) {
return true;
}
//暂存当前二维数组中该位置上的字符
let temp = board[x][y];
//改变该位置上的字符值,以此作为该字符被访问过的标记,这样比较节省空间,不用再开辟一个二维数组做标记
board[x][y] = '-';
// 对本字符上、右、下、左四个位置做深搜
let result = dfs(x - 1, y, k + 1) || dfs(x, y + 1, k + 1) || dfs(x + 1, y, k + 1) || dfs(x, y - 1, k + 1);
//当前字符深搜结束,去掉访问过的标记,即改为原来的字符,方便回溯后重新进行搜索
board[x][y] = temp;
//返回本轮的判断结果
return result;
}
}
讲一下思路,首先从二维数组中,同word字符串中的第一个字符word[0]相等的字符的位置开始进行深度优先遍历,即DFS。
第一步:先判断当前位置是否越界/当前位置的字符与word[k]是否不相等,符合的情况下直接返回false,结束当前的深搜。
第二步:此时未越界且当前位置上的字符与字符串中k位置上的的相等,判断k是否是字符串的长度,即是否已经比较到了最后一个字符,是的话返回true,结束深搜。
第三步:对当前位置board[x][y]进行一个访问过的标记,然后对该位置的上、右、下、左,顺时针四个方向深搜一遍,最后将深搜的结果进行一个综合,作为本次深搜的结果。去掉当前位置的访问标记,返回搜索结果。
本题有两个角度优化搜索时间,即字符串word太长,二维数组的所有字符的个数都匹配不到的情况,以及从二维数组中的哪个位置开始进行搜索,当当前字符与字符串中的第一个字符都不相等的情况下就没必要进行深搜了。
有一个角度优化内存消耗,直接更改当前位置上的字符来作为访问过的标记,就不用再开辟一个同样大小的二维数组了,从而节省了空间。