回溯——单词搜索
题目要求:
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
这道题是经典的深度优先搜索(DFS)+ 回溯问题,核心思路是:遍历网格的每一个单元格作为起点,向上下左右四个方向递归搜索,匹配单词的每一个字符,同时标记已访问单元格避免重复使用,匹配失败则回溯恢复状态。
代码核心解析
- 方向数组
DIRECTIONS定义了上下左右四个移动方向,简化代码,避免重复写四个方向的坐标计算 - 主函数逻辑
- 先做边界校验,网格为空直接返回false;
- 遍历网格每一个单元格,作为单词的起点;
- 调用DFS函数,只要有一个起点匹配成功,立即返回true。
- DFS + 回溯核心
- 终止条件:index == word.length(),说明单词所有字符都匹配完成,返回true;
- 剪枝条件:坐标越界、单元格已访问、字符不匹配->直接返回false(提前终止无效搜索)
- 标记访问:将当前单元格标记为已访问,防止重复使用;
- 递归搜索:向四个方向递归,匹配单词的下一个字符;
- 回溯恢复:当前路径匹配失败,取消当前单元格的访问标记,回到上一层继续搜索其他路径。
总结
- 解题核心是DFS + 回溯,通过标记数组避免单元格重复使用;
- 递归中做好边界剪枝,提升搜索效率;
- 匹配失败后必须回溯恢复状态,保证其他路径能正常使用该单元格。
完整Java代码实现如下:
public class WordSearch {
// 定义四个方向:上、下、左、右
private static final int[][] DIRECTIONS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public boolean exist(char[][] board, String word) {
// 边界判断:网格为空直接返回false
if (board == null || board.length == 0 || board[0].length == 0) {
return false;
}
int rows = board.length; // 网格行数
int cols = board[0].length; // 网格列数
// 标记数组:记录单元格是否被访问过
boolean[][] visited = new boolean[rows][cols];
// 遍历每一个单元格作为起点
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
// 从当前单元格开始搜索,匹配单词的第0个字符
if (dfs(board, word, i, j, 0, visited)) {
return true;
}
}
}
// 所有起点都搜索完,未找到单词
return false;
}
/**
* 深度优先搜索 + 回溯
* @param board 二维字符网格
* @param word 目标单词
* @param row 当前遍历的行
* @param col 当前遍历的列
* @param index 当前匹配到单词的第几个字符
* @param visited 访问标记数组
* @return 是否匹配成功
*/
private boolean dfs(char[][] board, String word, int row, int col, int index, boolean[][] visited) {
// 递归终止条件:index等于单词长度,说明全部字符匹配成功
if (index == word.length()) {
return true;
}
int rows = board.length;
int cols = board[0].length;
// 边界判断:行/列越界、已访问、当前字符不匹配 → 直接返回false
if (row < 0 || row >= rows || col < 0 || col >= cols
|| visited[row][col] || board[row][col] != word.charAt(index)) {
return false;
}
// 标记当前单元格为已访问(避免重复使用)
visited[row][col] = true;
// 向四个方向递归搜索下一个字符
for (int[] dir : DIRECTIONS) {
int newRow = row + dir[0]; // 新行
int newCol = col + dir[1]; // 新列
// 只要有一个方向匹配成功,直接返回true
if (dfs(board, word, newRow, newCol, index + 1, visited)) {
return true;
}
}
// 回溯:当前路径匹配失败,恢复未访问状态
visited[row][col] = false;
// 所有方向都匹配失败
return false;
}
// 测试示例
public static void main(String[] args) {
WordSearch solution = new WordSearch();
// 测试用例1
char[][] board1 = {
{'A','B','C','E'},
{'S','F','C','S'},
{'A','D','E','E'}
};
String word1 = "ABCCED";
System.out.println(solution.exist(board1, word1)); // 输出:true
// 测试用例2
String word2 = "SEE";
System.out.println(solution.exist(board1, word2)); // 输出:true
// 测试用例3
String word3 = "ABCB";
System.out.println(solution.exist(board1, word3)); // 输出:false
}
}
浙公网安备 33010602011771号