# 单词搜索 (Word Search) ## 题目描述 给定一个 `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 ``` ## 解题思路 ### 方法一:DFS + 回溯(推荐) **核心思想:**对每个位置进行 DFS,搜索是否存在匹配的单词路径。 **算法步骤:** 1. 遍历网格的每个位置 2. 如果当前位置字符匹配单词首字符,开始 DFS 3. DFS 过程中: - 标记当前已访问 - 向四个方向递归搜索 - 如果找到完整单词,返回 true - 回溯时撤销访问标记 ## 代码实现 ### Go 实现 ```go package main func exist(board [][]byte, word string) bool { m, n := len(board), len(board[0]) visited := make([][]bool, m) for i := range visited { visited[i] = make([]bool, n) } var dfs func(i, j, k int) bool dfs = func(i, j, k int) bool { // 找到完整单词 if k == len(word) { return true } // 边界检查或不匹配 if i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || board[i][j] != word[k] { return false } // 标记访问 visited[i][j] = true // 向四个方向搜索 found := dfs(i+1, j, k+1) || dfs(i-1, j, k+1) || dfs(i, j+1, k+1) || dfs(i, j-1, k+1) // 回溯:取消标记 visited[i][j] = false return found } for i := 0; i < m; i++ { for j := 0; j < n; j++ { if board[i][j] == word[0] && dfs(i, j, 0) { return true } } } return false } ``` ### Java 实现 ```java public class Solution { private boolean[][] visited; private int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; public boolean exist(char[][] board, String word) { int m = board.length, n = board[0].length; 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) && dfs(board, word, i, j, 0)) { return true; } } } return false; } private boolean dfs(char[][] board, String word, int i, int j, int k) { if (k == word.length()) { return true; } if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || visited[i][j] || board[i][j] != word.charAt(k)) { return false; } visited[i][j] = true; for (int[] dir : directions) { if (dfs(board, word, i + dir[0], j + dir[1], k + 1)) { visited[i][j] = false; return true; } } visited[i][j] = false; return false; } } ``` ## 复杂度分析 - **时间复杂度:** O(m × n × 4^L) - m × n 是网格大小 - L 是单词长度 - 最坏情况每个位置都要搜索 4 个方向 - **空间复杂度:** O(L) - 递归栈深度最大为 L - visited 数组 O(m × n) ## P7 加分项 ### 变形题目:单词搜索 II **LeetCode 212:** 给定一个 m x n 二维字符网格 board 和一个单词列表 words,返回所有在二维网格和字典中出现的单词。 ```go func findWords(board [][]byte, words []string) []string { // 构建 Trie 树 trie := buildTrie(words) result := []string{} for i := 0; i < len(board); i++ { for j := 0; j < len(board[0]); j++ { dfsBoard(board, i, j, trie, &result) } } return result } ```