package com.heu.wsq.leetcode.inoffer;
/**
* 剑指 Offer 12. 矩阵中的路径
* @author wsq
* @date 2021/4/13
* 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
* 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
* 例如,在下面的 3×4 的矩阵中包含单词 "ABCCED"(单词中的字母已标出)。
*
* 示例 1:
* 输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
* 输出:true
*
* 链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
*/
public class Offer12 {
/**
* 定义每个方格下一步可以移动的方向
*/
private int[][] direction = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
public boolean exist(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
// 创建一个m*n数组保存节点是否浏览的状态
boolean[][] visited = new boolean[m][n];
/**
* 可以从任一点出发,这里需要循环实现
*/
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(board[i][j] == word.charAt(0)){
if(dfs(board, i, j, visited, word, 0)){
return true;
}
}
}
}
return false;
}
private boolean dfs(char[][] board, int i, int j, boolean[][] visited, String word, int pos){
// 当满足以下条件时,直接返回false
// 主要包含i,j边界问题,以及是否已经访问和是否当前位置等于字符串当前需要匹配的字符
if(i < 0 || i >= board.length || j < 0 || j >= board[0].length
|| visited[i][j] || word.charAt(pos) != board[i][j]){
return false;
}
// 回溯最主要的就是遍历过一个点,首先将该点设置为已访问,遍历后则需要将其恢复到最初的样子
visited[i][j] = true;
pos += 1;
if(pos >= word.length()){
return true;
}
boolean flag = false;
for(int[] d: direction){
int x = i + d[0];
int y = j + d[1];
if(!flag){
flag = dfs(board, x, y, visited, word, pos);
}else{
break;
}
}
// 将该点的状态恢复到最初的样子
visited[i][j] = false;
return flag;
}
}