1. 题目
考察点
这道题的考察点是回溯法(backtracking)的应用。回溯法是一种常用的算法思想,它可以解决很多和搜索、组合、排列、子集、路径等相关的问题。回溯法的核心是递归和剪枝,递归是为了遍历所有可能的选择,剪枝是为了减少无效的选择,提高效率。回溯法需要掌握以下几个要点:
- 如何定义状态空间,也就是所有可能的选择。
- 如何定义递归函数,也就是回溯的过程。
- 如何定义终止条件,也就是找到一个解或者遍历完所有选择。
- 如何定义剪枝条件,也就是排除一些不满足条件的选择。
- 如何记录和恢复状态,也就是标记和取消标记访问过的位置。
这道题是一个典型的回溯法的问题,它要求我们在一个字符矩阵中寻找一个单词,我们可以把每个位置看作一个状态,每个方向看作一个选择,然后用回溯法来搜索所有可能的路径,如果找到一个匹配的单词,就返回true,否则返回false。我们需要注意边界条件和剪枝条件,以及如何记录和恢复访问矩阵。
2. 解法
思路
我的思路是使用回溯法(backtracking),也就是一种深度优先搜索(DFS)的变形,来在矩阵中寻找单词。回溯法的基本思想是,从一个起点开始,尝试所有可能的选择,如果发现某个选择不满足条件,就回退到上一个状态,继续尝试其他选择,直到找到一个满足条件的解或者遍历完所有选择。
代码逻辑
我的代码逻辑如下:
- 首先,检查边界情况,如果矩阵或单词为空,直接返回false。
- 然后,获取矩阵的行数和列数,并创建一个布尔矩阵来标记访问过的位置。
- 接着,遍历矩阵,对于每个位置,如果它和单词的第一个字符匹配,就调用一个辅助方法backtrack来进行回溯。如果backtrack返回true,说明找到了一个匹配的单词,就返回true。如果遍历完矩阵都没有找到匹配的单词,就返回false。
- 最后,定义辅助方法backtrack,它接收矩阵、单词、当前位置、当前索引和访问矩阵作为参数。它的逻辑如下:
- 检查基本情况,如果索引达到了单词的长度,说明已经找到了一个匹配的单词,就返回true。
- 检查边界条件,如果当前位置超出了矩阵的范围,或者已经访问过了,或者不和当前字符匹配,就返回false。
- 标记当前位置为已访问。
- 尝试四个方向:上、下、左、右,对于每个方向,递归调用backtrack,并将索引加一。如果任何一个方向返回true,就将结果赋值为true。
- 取消标记当前位置为已访问。
- 返回结果。
这样,就完成了回溯法的实现。希望这能帮助你理解我的代码。如果你还有其他问题,请随时提问。
具体实现
class Solution { public boolean exist(char[][] board, String word) { // 检查边界情况 if (board == null || board.length == 0 || board[0].length == 0 || word == null || word.length() == 0) { return false; } // 获取矩阵的维度 int m = board.length; int n = board[0].length; // 创建一个布尔矩阵来标记访问过的位置 boolean[][] visited = new boolean[m][n]; // 遍历矩阵,尝试从每个位置开始寻找单词 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { // 如果第一个字符匹配,开始回溯 if (board[i][j] == word.charAt(0)) { if (backtrack(board, word, i, j, 0, visited)) { return true; } } } } // 如果没有找到匹配,返回false return false; } // 辅助方法,执行回溯 private boolean backtrack(char[][] board, String word, int i, int j, int index, boolean[][] visited) { // 检查基本情况:如果索引达到单词的末尾,我们已经找到了一个匹配 if (index == word.length()) { return true; } // 检查边界条件:如果位置超出范围或已经访问过或不匹配当前字符,返回false if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || visited[i][j] || board[i][j] != word.charAt(index)) { return false; } // 标记当前位置为已访问 visited[i][j] = true; // 尝试四个方向:上,下,左,右 boolean res = backtrack(board, word, i - 1, j, index + 1, visited) || backtrack(board, word, i + 1, j, index + 1, visited) || backtrack(board, word, i, j - 1, index + 1, visited) || backtrack(board, word, i, j + 1, index + 1, visited); // 取消标记当前位置为已访问 visited[i][j] = false; // 返回结果 return res; } }