题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4
的矩阵中包含一条字符串bfce
的路径(路径中的字母用加粗标出)。
[["a","b","c","e"],
["s","f","c","s"],
["a","d","e","e"]]
但矩阵中不包含字符串abfb
的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:
输入:board = [["a","b"],["c","d"]], word = "abcd"
输出:false
解题思路
方法:DFS+剪枝
时间复杂度:$O(3^KMN)$ 最差情况下,需要遍历矩阵中长度为 $K$ 字符串的所有方案,时间复杂度为 $O(3^K)$;矩阵中共有 $MN$个起点,时间复杂度为 $O(MN)$。
空间复杂度:$O(K)$ 搜索过程中的递归深度不超过 $K$ ,因此系统因函数调用累计使用的栈空间占用 $O(K)$
代码如下
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
for(int i=0; i<board.size(); i++){
for(int j=0; j<board[i].size(); j++){
if(board[i][j] == word[0]){
if(dfs(i,j,board,word,0))
return true;
}
}
}
return false;
}
bool dfs(int i,int j,vector<vector<char>>& board, string word,int word_index){
if(i<0||i>=board.size()||j<0||j>=board[i].size() || board[i][j]!=word[word_index]){
return false;
}
if(word.size()-1 == word_index){
return true;
}
char tmp = board[i][j];
board[i][j] = '.';
bool judge = dfs(i+1,j,board,word,word_index+1)||dfs(i,j+1,board,word,word_index+1)
||dfs(i-1,j,board,word,word_index+1)||dfs(i,j-1,board,word,word_index+1);
board[i][j] = tmp;
return judge;
}
};
解法分析
- 深度优先搜索: 可以理解为暴力法遍历矩阵中所有字符串可能性。
DFS
通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。 - 剪枝: 在搜索中,遇到 这条路不可能和目标字符串匹配成功 的情况(例如:此矩阵元素和目标字符不同、此元素已被访问),则应立即返回,称之为 可行性剪枝 。
算法剖析
- 终止条件
- 行列越界
- 矩阵元素和目标元素不同
- 当前元素已经访问过
- 递推过程
- 遍历一遍二维数组,找到第一个匹配的元素
- 将当前元素暂存于
tmp
变量中,修改当前变量为/
。这么做代表这个元素已经访问过,后面无需再重新访问 - 对当前元素上下左右进行递归
- 将当前变量还原