矩阵中的路径
题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的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
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
解题思路
题目中说到移动路径可以是上下左右不限方向,只是不能回走到已经走过的路径,那么我们会联想到利用回溯法来解决这道题。回溯法非常适合解决由多个步骤组成的问题,而且每个步骤都有多个选项。回溯法一般用递归来实现。
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
回溯算法实际上一个类似枚举的搜索尝试过程,也就是一个个去试,我们解这道题也是通过一个个去试,遍历过程如下图所示:
这题我们只需将遍历走过的元素替换成‘\0’(字符串中不存在的值),这样就能很好的结合回溯法来满足题目要求了。
代码执行大致过程如下:
首先在board数组中找到一个位置,使得board[i][j] == word[0],可以作为搜索的入口。由于题目说明遍历过的元素不能重复访问,因此我们只需将遍历走过的元素替换成‘\0’(字符串中不存在的值)。然后通过上下左右搜索直到找到一个可行解即返回true,再继续进行下一元素的匹配搜索。若上下左右都没有元素与字符串字符匹配,那么就返回false,代表搜索失败。如果匹配到字符串末尾全部匹配上,则返回true,代表路径搜索成功。
代码展示
代码如下:
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
if(word.empty()||board.empty()||board[0].empty())
return false;
for(int i=0;i<board.size();i++)
{
for(int j=0;j<board[0].size();j++)
{
//回溯法
if(dfs(board,word,i,j,0))
return true;
}
}
return false;
}
private:
bool dfs(vector<vector<char>>& board,string& word,int i,int j,int w)
{
//判断索引是否越界或者当前值是否匹配,如果不满足则返回false
if(i<0||i>=board.size()||j<0||j>=board[0].size()||board[i][j]!=word[w])
return false;
//如果当前已经匹配到了字符串最后一位,则返回true。(-1是因为数组下标从0开始)
if(w==word.size()-1)
return true;
//保留当前的值到临时变量中
char tem=board[i][j];
//将当前值替换成数组中不可能存在的值(目的就是为了让这个值不再被遍历)
board[i][j]='\0';
//遍历当前索引的左右下上的值是否与字符串下一字符匹配(递归)
//若匹配一致则返回true,再继续进行下一字符的判断
if(dfs(board,word,i-1,j,w+1)
||dfs(board,word,i+1,j,w+1)
||dfs(board,word,i,j-1,w+1)
||dfs(board,word,i,j+1,w+1))
return true;
else
{
//如果不匹配则将当前值替换为原先值,返回false
board[i][j]=tem;
return false;
}
}
};
执行用时:24 ms, 在所有 C++ 提交中击败了96.00%的用户
内存消耗:7.7 MB, 在所有 C++ 提交中击败了86.01%的用户