LeetCode 79
https://leetcode.cn/problems/word-search/description/
难度:中等
高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/
网格图回溯。为了知道当前匹配到了第几个字母,需要三个参数 dfs(i, j, k)。
定义 dfs(i,j,k) 表示当前在 board[i][j] 这个格子,要匹配 word[k],返回在这个状态下最终能否匹配成功(搜索成功)。
- 如果 board[i][j] != word[k],匹配失败,返回 false。
- 否则,如果 k == len(word) − 1,匹配成功,返回 true。
- 否则,枚举 (i, j) 周围的四个相邻格子 (x, y),如果 (x, y) 没有出界,则递归 dfs(x, y, k + 1),如果其返回 true,则 dfs(i, j, k) 也返回 true。 如果递归周围的四个相邻格子都没有返回 true,则最后返回 false,表示没有搜到。
递归过程中,为了避免重复访问同一个格子,可以直接修改 board[i][j],将其置为空(或者 0),返回 false 前再恢复成原来的值(恢复现场)。注意返回 true 的时候就不用恢复现场了,因为已经成功搜到 word 了。
时间复杂度:\(O(mn3^k)\),其中 m 和 n 分别为 grid 的行数和列数,k 是 word 的长度。除了递归入口,其余递归至多有 3 个分支(因为至少有一个方向是之前走过的),所以每次递归(回溯)的时间复杂度为 \(O(3^k)\),一共回溯 O(mn) 次,所以时间复杂度为 \(O(mn3^k)\)。
空间复杂度:O(∣Σ∣+k)。其中 ∣Σ∣=52 是字符集合的大小。递归需要 O(k) 的栈空间。部分语言用的数组代替哈希表,可以视作 ∣Σ∣=128。
class Solution {
static constexpr int DIRS[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
public:
bool exist(vector<vector<char>>& board, string word){
int m = board.size(), n = board[0].size();
auto dfs = [&](auto &&dfs, int i, int j, int k) -> bool {
if (board[i][j] != word[k]) {
return false;
}
if (k + 1 == word.size()) {
return true;
}
char ch = board[i][j];
board[i][j] = 0;
for (auto &d: DIRS) {
int x = i + d[0];
int y = j + d[1];
if (0 <= x && x < m && 0 <= y && y < n && dfs(dfs, x, y, k + 1)) {
return true;
}
}
board[i][j] = ch;
return false;
};
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dfs(dfs, i, j, 0)) {
return true;
}
}
}
return false;
}
};