剑指OFFER题55------按牛客网通过率排序
时间:2019.1.10.1924
作者:Waitt
题目
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
时间限制:1秒 空间限制:32768K 热度指数:125939
解答
利用回溯法:回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
首先,遍历这个矩阵,我们很容易就能找到与字符串str中第一个字符相同的矩阵元素ch。然后遍历ch的上下左右四个字符,如果有和字符串str中下一个字符相同的,就把那个字符当作下一个字符(下一次遍历的起点),如果没有,就需要回退到上一个字符,然后重新遍历。为了避免路径重叠,需要一个辅助矩阵来记录路径情况。
下面代码中,当矩阵坐标为(row,col)的格子和路径字符串中下标为c的字符一样时,从4个相邻的格子(row,col-1)、(row-1,col)、(row,col+1)以及(row+1,col)中去定位路径字符串中下标为c+1的字符。
如果4个相邻的格子都没有匹配字符串中下标为c+1的字符,表明当前路径字符串中下标为c的字符在矩阵中的定位不正确,我们需要回到前一个字符串(c-1),然后重新定位。
一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到格式的位置(此时str[c] == ‘\0’)。
由于路径不能进入重复的格子,所以还需要定义和字符矩阵一样的布尔值矩阵,用来标识路径是否已经进入每个格子。
参考:https://cuijiahua.com/blog/2018/02/basis_65.html
class Solution {
public:
/*
其中下标c和矩阵a需要实时变化,而a本身为地址,地址本身并不会变化,变化的是地址指向的值,
所以c需要使用引用传递,而a使用值传递即可
*/
bool inpath(char* matrix, int rows, int cols, char* str,int row, int col, int &c,bool *a)
{
if(str[c]=='\0')
//注意此处的写法,为'\0'而非'/0',或者写成if(!str[c]),用来判断字符串是否到达末位
return 1;
if(a[row*cols+col]==1)//判断这个位置是否已经来过,注意位置的公式:row*cols+col
return 0;
bool b=0;
if(row>=0&&row<rows&&col>=0&&col<cols)//确保下标在允许范围内
{
if(matrix[row*cols+col]==str[c])
//此时矩阵坐标为(row,col)的格子和路径字符串中下标为c的字符一样
{
c++;
a[row*cols+col]=1;
b=inpath(matrix,rows,cols,str,row+1,col,c,a)||
inpath(matrix,rows,cols,str,row-1,col,c,a)||
inpath(matrix,rows,cols,str,row,col+1,c,a)||
inpath(matrix,rows,cols,str,row,col-1,c,a);
if(b==0)//说明4个相邻的格子都没有匹配字符串中下标为c+1的字符
{
c--;
a[row*cols+col]=0;
}
}
}
return b;
}
bool hasPath(char* matrix, int rows, int cols, char* str)
{
if(!matrix||rows<1||cols<1||!str)
return 0;
bool *a=new bool[rows*cols]();//a为用于判断是否来过的辅助矩阵
//此处也可用bool *a=new bool[rows*cols]{0};或者用memset(a,0,rows*cols);
int c=0;//c为当前字符串对应的下标
for(int row=0;row<rows;row++)
{
for(int col=0;col<cols;col++)
{
if(inpath(matrix,rows,cols,str,row,col,c,a))
return 1;
}
}
delete [] a;
return 0;
}
};
注意:其中下标c和矩阵a需要实时变化,而a本身为地址,地址本身并不会变化,变化的是地址指向的值,所以c需要使用引用传递,而a使用值传递即可。
易错点:
- ‘\0’容易写错成’/0’
- 下标的表达式为:row*cols+col