矩阵中的路径

剑指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使用值传递即可。

易错点:

  1. ‘\0’容易写错成’/0’
  2. 下标的表达式为:row*cols+col
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值