leetcode-79. 单词搜索
深度优先搜索(dfs)
回溯算法
题目详情
给定一个 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
我的代码:
不同于排列组合问题,本题采用的并不是修改输出方式,而是修改访问标记。在我们对任意位置进行深度优先搜索时,我们先标记当前位置为已访问,以避免重复遍历(如防止向右搜索后又向左返回);在所有的可能都搜索完成后,再回改当前位置为未访问,防止干扰其它位置搜索到当前位置。
class Solution
{
public:
void backtracking(int i, int j, vector<vector<char>>& board, string& word, bool &find, vector<vector<bool>>& visited, int pos)
{
if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size()) //越界
return;
if (visited[i][j] || find || board[i][j] != word[pos]) //访问过该字母||已经找到||该字母不是所要找的
return;
if (pos == word.size() - 1) //找够了,find置true
{
find = true;
return;
}
visited[i][j] = true; //该处字母已经访问过了
//从该处为起点上下左右搜索
//既然能运行到这里,那么肯定是找到了一个字母,不然上面某个语句就return了,所以pos+1
backtracking(i + 1, j, board, word, find, visited, pos + 1); //向下
backtracking(i - 1, j, board, word, find, visited, pos + 1); //向上
backtracking(i, j+1, board, word, find, visited, pos + 1); //向右
backtracking(i, j-1, board, word, find, visited, pos + 1); //向左
visited[i][j] = false; //回溯,将访问忘记
}
bool exist(vector<vector<char>>& board, string word)
{
if (board.empty())
return false;
int m = board.size(), n = board[0].size();
vector<vector<bool>> visited(m, vector<bool>(n, false)); //m*n个bool的visited
bool find = false; //初始化false
for (int i = 0; i < m; ++i) //遍历尝试每个起点
{
for(int j = 0; j < n; ++j)
{
backtracking(i, j, board, word, find, visited, 0);
}
}
return find;
}
};
涉及知识点:
1.深度优先搜索(dfs)
深度优先搜索(depth-first seach,DFS)在搜索到一个新的节点时,立即对该新节点进行遍历;因此遍历需要用先入后出的栈来实现,也可以通过与栈等价的递归来实现。对于树结构而言,由于总是对新节点调用遍历,因此看起来是向着“深”的方向前进。
2.回溯法
回溯法(backtracking)是优先搜索的一种特殊情况,又称为试探法,常用于需要记录节点状
态的深度优先搜索。通常来说,排列、组合、选择类问题使用回溯法比较方便。
顾名思义,回溯法的核心是回溯。在搜索到某一节点的时候,如果我们发现目前的节点(及
其子节点)并不是需求目标时,我们回退到原来的节点继续搜索,并且把在目前节点修改的状态
还原。这样的好处是我们可以始终只对图的总状态进行修改,而非每次遍历时新建一个图来储存
状态。在具体的写法上,它与普通的深度优先搜索一样,都有 [修改当前节点状态]→[递归子节
点] 的步骤,只是多了回溯的步骤,变成了 [修改当前节点状态]→[递归子节点]→[回改当前节点
状态]。