剑指 Offer 12. 矩阵中的路径

题目

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。
在这里插入图片描述
在这里插入图片描述

思路

小卡小课堂:DFS和回溯的区别

很多小伙伴分不清这两个的区别,网上也有很多专业的解释,这里我说一下我的理解:

  • 回溯是一种更通用的算法,回溯是DFS的一般形式
  • DFS是与搜索树/图结构相关的特定回溯形式,DFS是回溯的特殊形式
  • DFS扩展到一般问题,就变成了回溯;回溯使用在树/图问题上,就是DFS

本题是用回溯法/DFS+剪枝(经过上面的解释,在本题的树/图问题中,回溯就是DFS)

算法思想 设函数 check(i,j,k)表示判断以网格的 (i,j)位置出发,能否搜索到单词 word[k],其中k为单词下标索引, word[k]表示字符串 word的第 k 个字符。如果能搜索到,则返回 true,反之返回 false。函数 check(i,j,k)的执行步骤如下:

  • 如果 board[i][j]≠s[k],当前字符不匹配,直接返回 false
  • 如果当前已经访问到字符串的末尾,即k == s.length()-1,,且对应字符依然匹配,此时直接返回 true
  • 否则,遍历当前位置的所有相邻位置。如果从某个相邻位置出发,能够搜索到 word[k+1],则返回 true,否则返回 false
  • 这样,对每一个位置 (i,j)都调用函数 check(i,j,0)进行检查:只要有一处返回 true,就说明网格中能够找到相应的单词,否则说明不能找到。
  • 为了防止重复遍历相同的位置,需要额外维护一个与 board等大的 visited数组,用于标识每个位置是否被访问过。每次遍历相邻位置时,需要跳过已经被访问的位置。

java代码如下:

class Solution{
	public boolean exist(char[][] board, String word){
		int h = board.length, w = board[0].length;
		boolean[][] visited = new boolean[h][w];
		for(int i = 0; i < h; i++){
			for(int j = 0; j < w; j++){
				boolean flag = check(board, visited, i, j, word, 0);
				if(flag){
					return true;
				}
			}
		}
		return false;
	}
		
	public boolean check(char[][] board, boolean[][] visited, int i, int j, String s, int k){
		if(board[i][j] != s.charAt(k)){//如果当前位置不匹配直接返回false
			return false;
		} else if ( k == s.length() -1){//如果匹配完毕,则返回true
			return true;
		}
		visited[i][j] = true;//标记当前位置已访问过
		int[][] directions = {{0,1}, {0,-1}, {1,0}, {-1,0}};//定义遍历的四个方向
		boolean result = false;//记录最终结果
		for(int[] dir : directions){
			int newi = i + dir[0], newj = j + dir[1];//更新新的坐标
			if(newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length){//如果位置合法
				if(!visited[newi][newj]){//且该位置未被访问过
					boolean flag = check(board, visited, newi, newj, s, k + 1);//检查新位置,并检查匹配k+1是否成功
					if(flag){
						result = true;
						break;//找到一个匹配的位置即可进行下一轮位置循环
					}
				}
			}
		}
		//如果for循环没有找到合法的位置或者匹配成功的位置,则回退到之前位置
		visited[i][j] = false;
		return result;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HDU-五七小卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值