面试题12:矩阵中的路径

1 题目描述:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如[a b c e s f c s a d e e]是3*4矩阵,其包含字符串"bcced"的路径,但是矩阵中不包含“abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

2 解题思路:利用回溯法求解。
首先,在矩阵中任选一个格子作为路径的起点。假设矩阵中某个格子的字符为ch并且这个格子对应于路径上的第i个字符。如果路径上第i个字符不是ch,那么这个格子就不可能处在路径上的第i个位置。如果路径上的第i个字符正好是ch,就往相邻的格子寻找路径上第i+1个字符。除了在矩阵边界上的格子之外,每个格子都有4个相邻的格子。重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。
当在矩阵中定位了路径上n个字符的位置后,在与第n个字符对应的格子周围都没有找到第n+1个字符,则只好在路径上回到第n-1个字符,重新去寻找第n个字符由于路径不能重复进入格子,我们需要定义一个字符矩阵一样大小的布尔值矩阵,用来标记路径是否已经进入了相应格子。


 注:关于回溯法有模板,可以解决一类问题,回头自己要整理一下理解并掌握用好回溯法。

3 代码实现:

class Solution {
public:
    bool hasPath(char* matrix, int rows, int cols, char* str)
        {
        if(matrix==nullptr||rows<1||cols<1||str==nullptr)
            return false;
        int Pathlength=0;                            //递增索引指示待匹配的字符
        bool *visited=new bool [rows*cols];          //标志数组记录每个格子是否使用过
        memset(visited,0,rows*cols);                 //内存初始化函数:初始化为0
        for(int row=0;row<rows;row++)
        {
            for(int col=0;col<cols;col++)
            {
              //flag=hasPathCore(matrix,rows,row,cols,col,str,Pathlength,visited); //从每个格子为起始位置进行回溯求解
              if(hasPathCore(matrix,rows,row,cols,col,str,Pathlength,visited))     //只要找到一个解就返回true,所以上面的一句有问题,
                  return true;
            }
        }
        delete [] visited;
        return false;
    }
   bool hasPathCore(char* matrix,int rows,int row,int cols,int col,char* str,int& Pathlength,bool* visited)
    {
        if(str[Pathlength]=='\0')     //这句很重要,是回溯的终止条件
            return true;
        bool hasPath_=false;
       // if(row<rows && row>=0 && col<cols && col>=0 && matrix[row*rows+col]==str[Pathlength] && !visited[row*rows+col])  这里 出错了!!!
		if(row<rows && row>=0 && col<cols && col>=0 && matrix[row*cols+col]==str[Pathlength] && !visited[row*cols+col])
        {
            ++Pathlength;
            visited[row*cols+col]=true;
            hasPath_=hasPathCore(matrix,rows,row-1,cols,col,str,Pathlength,visited)||hasPathCore(matrix,rows,row,cols,col-1,str,Pathlength,visited)||hasPathCore(matrix,rows,row+1,cols,col,str,Pathlength,visited)||hasPathCore(matrix,rows,row,cols,col+1,str,Pathlength,visited);
            if(!hasPath_)
            {
                --Pathlength;
                visited[row*cols+col]=false;
            }
        }
        return hasPath_;
    }
};

4 问题分析:

记录下自己的调试分析,发现一个问题,要提前解决掉,就是在牛客网的平台上自己的代码能够提交测试通过,然而自己在vs2010中调试却不通过(震惊!自己的基础还是不行,字符数组定义这块出问题了!!!)所以,不仅要会在封装好接口的平台上写核心算法,还要会写出整个算法程序:包含头文件、主函数、类模块(算法)、以及测试用例。因为在华为笔试的时候是要写出包含头文件在内的完整代码,这里考验的就是基础编程能力,有很多细节问题需要注意。

#include<iostream>
#include<stdio.h>
#include<cstring>

using namespace std;
class Solution {
public:
   static bool hasPath(char* matrix, int rows, int cols, char* str)
    {
        if(matrix==nullptr||rows<1||cols<1||str==nullptr)
            return false;
        int Pathlength=0;                            //递增索引指示待匹配的字符
        bool *visited=new bool [rows*cols];          //标志数组记录每个格子是否使用过
        memset(visited,0,rows*cols);                 //内存初始化函数:初始化为0
        for(int row=0;row<rows;row++)
        {
            for(int col=0;col<cols;col++)
            {
              //flag=hasPathCore(matrix,rows,row,cols,col,str,Pathlength,visited); //从每个格子为起始位置进行回溯求解
              if(hasPathCore(matrix,rows,row,cols,col,str,Pathlength,visited))     //只要找到一个解就返回true,所以上面的一句有问题,
                  return true;
            }
        }
        delete [] visited;
        return false;
    }
private:
   static bool hasPathCore(char* matrix,int rows,int row,int cols,int col,char* str,int& Pathlength,bool* visited)
    {
        if(str[Pathlength]=='\0')     //这句很重要,是回溯的终止条件
            return true;
        bool hasPath_=false;
       // if(row<rows && row>=0 && col<cols && col>=0 && matrix[row*rows+col]==str[Pathlength] && !visited[row*rows+col])  这里 出错了!!!
		if(row<rows && row>=0 && col<cols && col>=0 && matrix[row*cols+col]==str[Pathlength] && !visited[row*cols+col])
        {
            ++Pathlength;
            visited[row*cols+col]=true;
            hasPath_=hasPathCore(matrix,rows,row-1,cols,col,str,Pathlength,visited)||hasPathCore(matrix,rows,row,cols,col-1,str,Pathlength,visited)||hasPathCore(matrix,rows,row+1,cols,col,str,Pathlength,visited)||hasPathCore(matrix,rows,row,cols,col+1,str,Pathlength,visited);
            if(!hasPath_)
            {
                --Pathlength;
                visited[row*cols+col]=false;
            }
        }
        return hasPath_;
    }

};

 //bool hasPathCore(char* matrix,int rows,int row,int cols,int col,char* str,int& Pathlength,bool* visited);
 //bool hasPath(char* matrix, int rows, int cols, char* str)
 //   {
 //       if(matrix==nullptr||rows<1||cols<1||str==nullptr)
 //           return false;
 //       int Pathlength=0;                            //递增索引指示待匹配的字符
 //       bool *visited=new bool [rows*cols];          //标志数组记录每个格子是否使用过
 //       memset(visited,0,rows*cols);                 //内存初始化函数:初始化为0
 //       for(int row=0;row<rows;row++)
 //       {
 //           for(int col=0;col<cols;col++)
 //           {
 //             //flag=hasPathCore(matrix,rows,row,cols,col,str,Pathlength,visited); //从每个格子为起始位置进行回溯求解
 //             if(hasPathCore(matrix,rows,row,cols,col,str,Pathlength,visited))     //只要找到一个解就返回true,所以上面的一句有问题,
 //                 return true;
 //           }
 //       }
 //       delete [] visited;
 //       return false;
 //   }
 //bool hasPathCore(char* matrix,int rows,int row,int cols,int col,char* str,int& Pathlength,bool* visited)
 //   {
 //       if(str[Pathlength]=='\0')     //这句很重要,是回溯的终止条件
 //           return true;
 //       bool hasPath_=false;
 //      // if(row<rows && row>=0 && col<cols && col>=0 && matrix[row*rows+col]==str[Pathlength] && !visited[row*rows+col])  这里 出错了!!!
	//	if(row<rows && row>=0 && col<cols && col>=0 && matrix[row*cols+col]==str[Pathlength] && !visited[row*cols+col])
 //       {
 //           ++Pathlength;
 //           visited[row*cols+col]=true;
 //           hasPath_=hasPathCore(matrix,rows,row-1,cols,col,str,Pathlength,visited)||hasPathCore(matrix,rows,row,cols,col-1,str,Pathlength,visited)||hasPathCore(matrix,rows,row+1,cols,col,str,Pathlength,visited)||hasPathCore(matrix,rows,row,cols,col+1,str,Pathlength,visited);
 //           if(!hasPath_)
 //           {
 //               --Pathlength;
 //               visited[row*cols+col]=false;
 //           }
 //       }
 //       return hasPath_;
 //   }


int main()
{
	//Test1:(错误的赋值)
	char a[]={'A','B','C','E','S','F','C','S','A','D','E','E'};      //这里为什么不对?因为这种字符串赋值末尾还有个'\0',实际字符串长度不是12,而是13.
	char str[]={'B','C','C','E','D'};                               //这种字符串初始化方式,不会自动在末尾加'\0',而我们要求的字符串操作一般是以'\0'
	cout<<Solution::hasPath(a,3,4,str)<<endl;                      //作为结束字符串结束的标志的,没有'\0'结束符,我们操作的时候不知道字符串的末尾是什么
	                                                                 
	//修正Test1:
	char a[]={'A','B','C','E','S','F','C','S','A','D','E','E','\0'};    
	char str[]={'B','C','C','E','D','\0'};
	cout<<Solution::hasPath(a,3,4,str)<<endl;

	//Test2:
	/*char a[]="ABCESFCSADEE";
	char str[]="BCCED";
	cout<<Solution::hasPath(a,3,4,str)<<endl;*/

	//通过测试发现上述Test1有问题,本来应该测试通过的,结果Test1不通过,然鹅Test2却通过。

	//Test3: 
	/* char* matrix = "ABTGCFCSJDEH";
	 char* str = "BFCE";
	 cout<<hasPath(matrix,3,4,str)<<endl;*/

	
       //Test4: 
	/* char matrix[] = "ABTGCFCSJDEH";
	 char str[] = "BFCE";
	 cout<<hasPath(matrix,3,4,str)<<endl;*/
	return 0;
}

学习:上面的测试过程出问题的关键就是自己在构造测试用例的时候,因为对字符数组的初始化及赋值操作基础掌握不好,而导致的错误,因此也学习了字符数组的初始化及赋值操作。

1.字符数组初始化
在C语言中,字符串是当做字符数组来处理的;所以字符串有两种声明方式,一种是字符数组,一种是字符指针。

字符数组初始化

1 char parr[] = "zifuchuanshuzu";
2 char charr[] = { 'z','i','f','u','c','h','u','a','n','s','h','u','z','u' };

这是字符数组初始化的两种方式,但是这两种方式其实是不等价的;他们的数组长度不同。

 

2.字符指针

在C语言中我们也可以使用字符指针来存储字符串。

  • 字符指针初始化
char* str="zifuchuanshuzu";

关于字符数组初始化及赋值见博客https://blog.csdn.net/u011028771/article/details/52622721 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值