一、单词搜索问题
1. 问题描述
在一个二维字符数组 grid 中,判断是否存在给定的目标字符串 target ,可以从任意位置开始,按照上下左右四个方向进行搜索,每个位置的字符只能使用一次。
2. 代码实现
class Solution {
public:
bool wordPuzzle(vector<vector<char>>& grid, string target) {
rows = grid.size();
cols = grid[0].size();
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
if(dfs(grid, target, i, j, 0)) return true;
}
}
return false;
}
private:
int rows, cols;
bool dfs(vector<vector<char>>& grid, string target, int i, int j, int k) {
if(i >= rows || i < 0 || j >= cols || j < 0 || grid[i][j] != target[k]) return false;
if(k == target.size() - 1) return true;
grid[i][j] = '\0';
bool res = dfs(grid, target, i + 1, j, k + 1) ||
dfs(grid, target, i - 1, j, k + 1) ||
dfs(grid, target, i, j + 1, k + 1) ||
dfs(grid, target, i, j - 1, k + 1);
grid[i][j] = target[k];
return res;
}
};
3. 代码分析
-
在
wordPuzzle函数中,遍历二维数组的每个位置,从每个位置开始调用 dfs 函数进行深度优先搜索。 -
dfs函数中:
-
首先通过一系列条件判断
( i >= rows || i < 0 || j >= cols || j < 0 || grid[i][j] != target[k] )检查当前位置是否越界或字符不匹配,若满足则返回 false 。 -
当 k 等于
target.size() - 1时,说明已经匹配到目标字符串的最后一个字符,返回 true 。 -
将当前位置字符标记为 '\0' ,表示已访问,防止重复访问。
-
向上下左右四个方向递归调用 dfs 函数继续搜索,并使用逻辑或 || 组合结果。
-
搜索完成后,将当前位置字符恢复为原来的值
( grid[i][j] = target[k]; ),以便后续其他路径的搜索。
二、深度优先搜索(DFS)
1. 定义
深度优先搜索是一种用于遍历或搜索图或树的算法。它从某个起始节点开始,沿着一条路径尽可能深地探索下去,直到无法继续或达到目标节点,然后回溯到上一个节点,继续探索其他路径。
2. 适用场景
-
迷宫问题:寻找从起点到终点的路径。
-
图的遍历:如连通分量的查找、拓扑排序等。
-
回溯算法:在搜索过程中需要记录路径和状态,并且可以回溯到之前状态的问题,如八皇后问题、数独求解等。
3. 实现方式
-
递归实现:通过递归函数不断调用自身,实现深度优先搜索。每次递归时,处理当前节点,并递归处理相邻节点。
-
栈实现:使用栈数据结构模拟递归过程,将节点入栈和出栈,实现深度优先搜索。
4. 特点
-
优点:
-
能够快速找到解,特别是在解的深度较浅的情况下。
-
对于某些问题(如树的遍历),实现简单直观。
-
缺点:
-
可能会陷入无限循环(在没有正确处理的情况下)。
-
在搜索空间较大时,可能会消耗大量的内存(递归深度过深)。