问题描述
链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。
思路
首先整体思路是DFS这肯定是没错的,所以基本上也是就在DFS的模板上修改。
但是如果只是单纯的使用模板的话会导致有些情况搜索不到,因为我们修改的visited数组会导致下一个起始位置开始的遍历无法遍历所有可能。
visited数组的作用:
- 在DFS搜素的整体可能性上来说,避免重复搜索导致效率降低(剪枝——效率问题);
- 在单次DFS搜索中,避免两次递归重复调用(形成递归环),导致Stack Overflow(正确性问题).
而在这道题中,我们不能让作用1生效,避免一个起点的遍历情况影响另一个起点的遍历情况。
但是如果没有作用2,那么DFS无法执行,所以这道题要用回溯的思想,在递归结束后(回溯的过程),把visited数组修改回去,这样作用1就不会生效。由于已经在回溯了,此时visited数组的状态变化不会执行的过程产生影响。
Code
class Solution {
public boolean exist(char[][] board, String word) {
if (word.length() == 0) {
return false;
}
boolean[][] visited = new boolean[board.length][board[0].length];
char[] chs = word.toCharArray();
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == chs[0]) {
if (DFS(board, chs, 0, i, j, visited)) {
return true;
}
}
}
}
return false;
}
public boolean DFS(char[][] board, char[] chs, int idx, int x, int y, boolean[][] visited) {
if (idx == chs.length) {
return true;
}
if (x < 0 || y < 0 || x >= board.length || y >= board[0].length) return false;
// 保证作用1生效
if (visited[x][y]) {
return false;
}
if (board[x][y] != chs[idx]) {
return false;
}
visited[x][y] = true;
boolean res =
DFS(board, chs, idx+1, x-1, y, visited) ||
DFS(board, chs, idx+1, x+1, y, visited) ||
DFS(board, chs, idx+1, x, y-1, visited) ||
DFS(board, chs, idx+1, x, y+1, visited);
// 回溯
visited[x][y] = false;
return res;
}
}