2.题目描述:
给定一个 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 仅由大小写英文字母组成
3. 解法:
算法思路:
我们需要假设每个位置的元素作为第一个字母,然后向相邻的四个方向进行递归,并且不能出现重复使用同一个位置的元素。通过深度优先搜索的方式,不断地枚举相邻元素作为下一个字母出现的可能性,并在递归结束时回溯,直到枚举完所有可能性,得到正确的结果。
递归函数设计:bool dfs(int x, int y, int step, vector<vector<char>>& board, string word, vector<vector<bool>>& vis, int &n, int &m, int &len)
参数:x(当前需要进行处理的元素横坐标),y(当前需要进行处理的元素横坐标),step(当前已经处理的元素个数),word(当前的字符串状态);
返回值:当前坐标元素作为字符串中下标 step 的元素出现是否可以找到成立的字符串。
函数作用:判断当前坐标的元素作为字符串中下标 step 的元素出现时,向四个方向传递,查找是否存在路径结果与字符串相同。
递归函数流程:
1. 遍历每个位置,标记当前位置并将当前位置的字母作为首字母进行递归,并且在回溯时撤回标记。
2. 在每个递归的状态中,我们维护一个步数 step,表示当前已经处理了几个字母。
◦ 若当前位置的字母与字符串中的第 step 个字母不相等,则返回 false。
◦ 若当前 step 的值与字符串长度相等,表示存在一种路径使得 word 成立,返回 true。
3. 对当前位置的上下左右四个相邻位置进行递归,若递归结果为 true,则返回 true。
4. 若相邻的四个位置的递归结果都为 false,则返回 false。
•
特别地,如果使用将当前遍历到的字符赋值为空格,并在回溯时恢复为原来的字母的方法,则在递归时不会重复遍历当前元素,可达到不使用标记数组的目的。
Java算法代码:
class Solution {
boolean[][] vis;
int m, n;
char[] word;
public boolean exist(char[][] board, String _word) {
m = board.length; n = board[0].length;
word = _word.toCharArray();
vis = new boolean[m][n];
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++){
if(board[i][j] == word[0]){
vis[i][j] = true;
if(dfs(board,i,j,1)) return true;
vis[i][j] = false;
}
}
return false;
}
int []dx = {0,0,-1,1};
int []dy = {1,-1,0,0};
public boolean dfs(char[][] board,int i,int j,int pos){
if(pos == word.length){
return true;
}
// 上下左右去匹配 word[pos]
// 利用向量数组,一个 for 搞定上下左右四个方向
for(int k = 0;k<4;k++){
int x = i +dx[k],y=j+dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && board[x][y]== word[pos]){
vis[x][y] = true;
if(dfs(board,x,y,pos+1)) return true;
vis[x][y] = false;
}
}
return false;
}
}
运行结果:
递归展开:
这里细节挺多的。
比如找所有的开始字母然后分别进行递归。
从正确开始字母,然后上下左右,都去进行遍历。
返回值的用法(和上个题目一样)。
逻辑展开:当能懂逻辑展开之后,自己进行展开,可以直接写出答案(有章法,而不是说,像是开始的时候,人脑的思考逻辑)
---------------------------------------------------------------------------------------------------------------------------------
记住,相信你的递归函数,它可以做到!
记住,不理解时候,去尝试手动展开!
记住,逻辑展开(你不可能对所有的题目都进行手动展开)!