一、题目
给定一个 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
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成
二、题解
这题确实没接触过,没什么思路,直接看的leetcode题解,思路参照leetcode-cn.com/problems/ju…
理一下总体思路,首先此题本质上就是搜索一个矩阵,然后找到里面是否存在一个单词和word中的一样,那么我们肯定先要把字符串word化成一个字符数组wordArray,然后用wordArray[k]和board[i][j]逐一比较,然后相等则k++,最后看k是否等于wordArray.length-1,相等则全部比对完毕,返回true。
那怎么“搜索”这个矩阵就成了关键问题:题解给的方法是dfs(深度优先搜索),通过递归,先朝一个方向搜到不能再搜,然后再回来,再换一个方向。然后在遇到匹配不成功的情况时候,就要直接返回false,结束这个方向的搜索。
三、代码(js)
/**
* @param {character[][]} board
* @param {string} word
* @return {boolean}
*/
// split功能测试
// let word = "abcdefghijk"
// let words = word.split("");
// console.log(words);
// 样例测试
// let board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]];
// let word = "ABCCED";
var exist = function(board, word) {
//先把word字符串转换为字符数组 用split函数
let wordArray = word.split("");
for(let i = 0 ,rows = board.length; i < rows; i++)
{
for(let j =0,cols = board[0].length ;j< cols ;j++)
{
if(dfs(board,wordArray,i,j,0)) return true
}
}
return false
};
let dfs = function(board,wordArray,i,j,k)
{
//当数组超限,或者字符不匹配(board[i][j]不等于wordArray[k])时,直接返回false
if(i<0||i>board.length-1||j<0||j>board[0].length-1||board[i][j]!=wordArray[k])
return false;
//当此时字符匹配 且 此时k==wordArray.length-1时,就说明wordArray的全部字符匹配成功,返回true
if(k==wordArray.length-1)
return true;
//当此时字符匹配 且 wordArray的字符还没有匹配完时,就递归继续往深处搜索
//暂时先赋值0再往深处找,避免回头找、避免重复使用 (标记为已访问)
board[i][j] = '\0';
let res = dfs(board,wordArray,i+1,j,k+1)
||dfs(board,wordArray,i-1,j,k+1)
||dfs(board,wordArray,i,j+1,k+1)
||dfs(board,wordArray,i,j-1,k+1)
//这条路的最深处的每个方向查找完之后,回溯这个值,这样能找到回去的路 (相当于取消标记)
board[i][j]=wordArray[k];
return res;
}
// 输出测试
// console.log(exist(board,word));
四、拓展思考
讲几个要注意的点:
1.字符串word先改成字符数组wordArray
2.一开始我对于这段代码的理解有点误解吗,我以为是先从起点遍历一周再往深走,这是大错特错的!其实是先从起点直接先走到底,走到底之后再遍历四周,遍历这个节点的四周之后再回溯,然后再遍历上一个节点的四周,再回溯,最后回到起点。
let res = dfs(board,wordArray,i+1,j,k+1)
||dfs(board,wordArray,i-1,j,k+1)
||dfs(board,wordArray,i,j+1,k+1)
||dfs(board,wordArray,i,j-1,k+1)
3.感觉这段代码还是有点难理解,个人理解就是board[i][j]='\0'就是将当前这个值标记为已访问,这样就不会出现重复使用的情况,然后当遍历完这个值的四周之后,再把当前这个值值赋回去(board[i][j]=wordArray[k]),相当于取消标记了。
board[i][j] = '\0';
let res = dfs(board,wordArray,i+1,j,k+1)
||dfs(board,wordArray,i-1,j,k+1)
||dfs(board,wordArray,i,j+1,k+1)
||dfs(board,wordArray,i,j-1,k+1)
board[i][j]=wordArray[k];
题目来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ju…