79. 单词搜索

238 阅读2分钟

题目介绍

力扣79题:leetcode-cn.com/problems/wo…

image.png

image.png

image.png

回溯

  • SEE为例,首先要选起点:遍历矩阵,找到起点S
  • 起点可能不止一个,基于其中一个S,看看能否找出剩下的"EE"路径。
  • 下一个字符E有四个可选点:当前点的上、下、左、右。
  • 逐个尝试每一种选择。基于当前选择,为下一个字符选点,又有四种选择。
  • 每到一个点做的事情是一样的。DFS 往下选点,构建路径。
  • 当发现某个选择不对,不用继续选下去了,结束当前递归,考察别的选择。

image.png

接着关注当前考察的点,处理它,其他丢给递归子调用去做。判断当前选择的点,本身是不是一个错的点。剩下的字符能否找到路径,交给递归子调用去做。

如果当前点是错的,不用往下递归了,返回false。否则继续递归四个方向,为剩下的字符选点。 那么,哪些情况说明这是一个错的点:

  • 当前的点,越出矩阵边界。
  • 当前的点,之前访问过,不满足「同一个单元格内的字母不允许被重复使用」。
  • 当前的点,不是目标点,比如你想找 E,却来到了 D

image.png

代码如下:

class Solution {
    public boolean exist(char[][] board, String word) {
        // 类似于在二叉树找单链表 不同点在于二叉树只有向下一个方向
        // 因此二叉树不需要回溯修改已访问节点
        // 但是网格有四个方向,只能上下左右,需要回溯修改节点访问状态
        
        // visited 数组防止重复访问
        int m = board.length;
        int n = board[0].length;
        //存储节点是否被访问过
        boolean[][] visited = new boolean[m][n];
        
        // 每个格子都可能是起点
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (dfs(board, i, j, 0, word, visited))
                    return true;
            }
        }
        return false;
    }

    public boolean dfs(char[][] a, int row, int col, int i, String word, boolean[][] visited) {

        // 不在网格内
        if (!inArea(a, row, col))
            return false;
        
        // 重复访问
        if (visited[row][col] == true)
            return false;

        // 当前字符不等
        if (a[row][col] != word.charAt(i))
            return false;

        //i为当前比较的字符下标,全部字符匹配
        if (i == word.length() - 1)
            return true;
        
        // 当前字符匹配 做访问标记
        visited[row][col] = true;
        
        // 当前点四个方向匹配下一个字符
        boolean f = dfs(a, row - 1, col, i + 1, word, visited) ||
            dfs(a, row + 1, col, i + 1, word, visited) ||
            dfs(a, row, col - 1, i + 1, word, visited) ||
            dfs(a, row, col + 1, i + 1, word, visited);
        
        if (f == true)
            return true;
        
        //回溯修改当前不能访问的点 但是接下来的方向可以访问它
        visited[row][col] = false;
        return false;
    }

    public boolean inArea(char[][] a, int i, int j) {
        if (0 <= i && i < a.length && 0 <= j && j < a[0].length)
            return true;
        return false;
    }
}