JZ65 矩阵中的路径

目录

本文是参考牛客网的官方题解结合自己理解写的,官方题解:牛客官方题解
其中官方题解采用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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题描述: 给定一棵二叉树和一个整数目标值,找出所有从根节点到叶子节点的路径,使得路径上的节点值之和等于目标值。 解题思路: 我们可以使用深度优先搜索(DFS)的思想来解决这个问题。具体步骤如下: 1. 定义一个列表path,用于存储当前的路径。 2. 递归遍历每个节点: a. 将当前节点添加到path。 b. 如果当前节点是叶子节点且路径上的节点值之和等于目标值,则将当前路径添加到结果。 c. 递归遍历当前节点的左子树和右子树。 d. 在递归结束后,将当前节点从path移除,以便开始探索其他路径。 3. 返回结果列表,即所有路径和等于目标值的路径。 代码实现: ``` class Solution: def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]: def dfs(node, path, target): if not node: return path.append(node.val) if not node.left and not node.right and sum(path) == target: res.append(path.copy()) dfs(node.left, path, target) dfs(node.right, path, target) path.pop() res = [] dfs(root, [], targetSum) return res ``` 以上代码,我们定义了一个辅助函数dfs来进行递归遍历。在遍历的过程,我们使用列表path来存储当前路径,如果路径上的节点值之和等于目标值,则将当前路径添加到结果列表res。最后返回结果res。 时间复杂度分析: 假设二叉树的节点数为n,则时间复杂度为O(n),因为我们需要遍历每个节点一次。需要注意的是,在每个节点处,我们都会调用sum函数来计算当前路径的节点值之和,因此总的时间复杂度还需要考虑到sum函数的时间复杂度。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值