目录
本文是参考牛客网的官方题解结合自己理解写的,官方题解:牛客官方题解
其中官方题解采用C++,博主已入JAVA坑,理解官方题解意思,使用JAVA写的
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如
矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
题目理解
给定一个二维字符串矩阵matrix,和一个字符串str,判断str是否可以在mat中匹配到一条路径,注意路径一般是指连续的,对于路径搜索,一般还是首先会想到DFS,对于BFS搜索他是在一圈中搜索,在二维矩阵中,他的路径不是连读,可以参考上一题机器人运动范围的BFS顺序,可以看到构不成一条路径.
方法:DFS遍历
DFS的模板是:
dfs(){
// 第一步,检查下标是否满足条件
// 第二步:检查是否被访问过,或者是否满足当前匹配条件
// 第三步:检查是否满足返回结果条件
// 第四步:都没有返回,说明应该进行下一步递归
// 标记
dfs(下一次)
// 回溯
}
main() {
for (对所有可能情况) {
dfs()
}
}
那么在知道模板之后,我们就对照模板分析,
第一步的检查下标是否满足条件,大家应该都会;
第二步就是是否被访问过,需要我们开一个数组做标记,做题最后都按照一个流程来,就开一个mark[]矩阵,注意题解给的输入matrix是一个一维矩阵,对应mark[]也是一维的,或者是满足匹配条件,在剪绳子中就是检查下标之和,这里就是两个字符是否匹配
第三步:检查是否满足返回条件,返回条件在这里就是我们成功匹配到str的最后一个字符
第四步:都没有返回,应该进行下一步递归,做相应的标记,以及str字符串位置进行移动,匹配下一个字符串
第五步再进行下一步的递归,在这里我们加一个判断,只要其中有匹配到的格子,就按照这个格子上下左右搜索.
可以观察程序输出的x,y,可以加深理解dfs遍历的顺序
package Matrix_Path;
import java.util.Scanner;
import java.util.*;
/*
* dfs(){
* 第一步,检查下标是否满足条件
* 第二步:检查是否被访问过,或者是否满足当前匹配条件
* 第三步:检查是否满足返回结果条件
* 第四步:都没有返回,说明应该进行下一步递归
* 标记
* dfs(下一次)
* 回溯
}
*/
public class DFS_Path_JZ65 {
/*四个方向
* x+dir[i+1] y+dir[i]
* x+0 y+1 右
* x-1 y+0 上
* x+0 y-1 左
* x+1 y+0 下
* 想把右,下,左,上排列出来,但是尝试了下,会出现重复
*/
public int[] dir={1,0,-1,0,1};
public int pos=0;
public boolean dfs(int x,int y,int rows,int cols, int pos,int[] mark,char[] matrix,String str) {
//可以观察 深度度优先的遍历顺序
System.out.println("x y:"+x+" "+y);
//先检查下标是否越界
if(x<0||x>=rows||y<0||y>=cols) {
return false;
}
int index=x*cols+y;
//再检查是否被访问过,以及是否匹配到当前字符,观察匹配到那个字符
System.out.println(str.charAt(pos));
if(mark[index]==1||matrix[index]!=str.charAt(pos))
{
return false;
}
//经过上面检查表明已经匹配了,标记,开始匹配下一个
mark[index]=1;
pos++;
//判断是否匹配到最后末尾,如果是,表明成功匹配
//注意上面经过++,pos匹配到最后一个会有+1操作
System.out.println(pos);
if(pos==str.length()) {
return true;
}
//注意这里递归,当其中字符串匹配的时候就输出true,才能够继续在该格子的上下左右搜索
for(int i=0;i<4;i++) {
if(dfs(x+dir[i+1],y+dir[i],rows,cols,pos,mark,matrix,str)){
return true;
}
}
//从该起点搜索无法匹配 str,就开始准备下一次新起点的搜索,将访问状态重新置为0;
System.out.println("reset x y:"+x+" "+y);
mark[index]=0;
//本次从x,y作为起点搜索失败
return false ;
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.print("Enter a row:");
int rows=sc.nextInt();
//int rows=3;
System.out.println("Enter a columns:");
int columns=sc.nextInt();
//int columns=4;
System.out.println("Enter a char Matrix :");
String s;
int size=rows*columns;
char[] matrix= new char[size];
//char[] matrix= {'a', 'b' ,'c' , 'e', 's', 'f', 'c', 's', 'a', 'd', 'e','e'};
int[] mark=new int[size];
for(int i=0;i<size;i++) {
s=sc.next();
matrix[i]=s.charAt(0);
mark[i]=0;
}
System.out.println("Enter a String :");
String str=sc.next();
DFS_Path_JZ65 d=new DFS_Path_JZ65();
boolean output=false;
//包含的路径可能是从任意一个格子作为起点,所以需要把所有格子遍历一次
for(int i=0;i<rows;i++) {
for(int j=0;j<columns;j++) {
System.out.println("i j:"+i+" "+j);
//一旦其中搜到一条包含字符串的路径就终止
if(d.dfs(i,j,rows,columns,d.pos,mark,matrix,str))
{
output=true;
break;
}
}
}
System.out.println(output);
}
}
运行结果观察
我们以字符串bcced的匹配为例,在0,0位置矩阵中字符为a不匹配,该(0,0)格子作为起点搜索失败,主函数中循环到(0,1)作为起点,可以匹配到字符b(pos=1),然后dfs向右搜索到(0,2),同样可以匹配字符c(pos=2),再向右搜索,此时字符不匹配,开始回溯,注意我们的搜索方向是右,上,左,下,此时回到(0,2),观察它的上(-1,2),左(0,1),下(1,2),此时(1,2)位置匹配正确(pos=3),开始沿(1,2)的右(1,3),上(0,2),左(1,1),下(2,2)搜索,同样(2,2)处匹配正确(pos=4),同样按照右(2,3),上(1,2),左(2,1)搜索,能够匹配正确,pos=5,匹配结束.
对应的abcb大家可以观察程序执行逻辑,dfs递归查找的路径
wo,en