Skip to content
本页目录

12-矩阵中的路径

题目描述

https://leetcode.cn/problems/ju-zhen-zhong-de-lu-jing-lcof/

给定一个 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

示例 2:

输入:board = [["a","b"],["c","d"]], word = "abcd"
输出:false

提示:

1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成

注意:本题与主站 79 题相同:https://leetcode.cn/problems/word-search/

思路分析

回溯法

第1步,首先 for循环整个数组,任意一个字符都可能是开始。

第2步,传入当前坐标和 word 的 index,如果当前的值和 word index的字符是相等的,则继续下一步

第3步,判断当前坐标的相邻的4个单元格,有任何一个是和word index是相等的,则继续下一步递归判断

因为不能重复放置,所以需要另外一个数组记录了放置的值

第4步,如果执行到 word index的结束,则返回true,如果相邻的单元格已经被放置,或者和下一个word index的值都不相等,则return false

实现代码

csharp
public class Solution {


    // 基本思路:开辟一个一样的数组用来存储是否被访问过
    // 从第一个单元格循环
    // dfs + 回溯;
    // 使用二维布尔数组记录之前的位置是否已经被访问过,如果已经被访问过的话,则在 dfs 的过程中,直接 return false 即可。也就是说,此路已经不通了;
    // 如果当前遍历到的字符不等于 board[i][j] 位置上的字符,那么说明此路也是不通的,因此返回 false;
    // 至于递归结束的条件:如果指针 start 能够来到 word 的最后一个字符,那么说明能够在矩阵 board 中找到一条路径,此时返回 true;
    // 在遍历到当前 board[i][j] 的时候,首先应将该位置的 visited[i][j] 设置为 true,表明访问过;
    // 然后,递归地去 board[i][j] 的上下左右四个方向去找,剩下的路径;
    // 在 dfs 的过程当中,如果某条路已经不通了,那么那么需要回溯,也就是将 visited[i][j] 位置的布尔值重新赋值为 fasle;
    // 最后,返回 ans 即可。

    private bool IsExist(char[][] board, int[][] visited, string word, int boardRow, int boardCol, int wordIndex){
        //如果全访问完了,说明存在
        if(wordIndex >= word.Length){
            return true;
        }
        if(boardRow < 0 || boardRow >= board.Length || boardCol < 0 || boardCol >= board[0].Length || board[boardRow][boardCol] != word[wordIndex] || visited[boardRow][boardCol] == 1 ){
            //如果越界直接返回 false
            return false;
        }
        visited[boardRow][boardCol] = 1 ;
        //探测四个方向
        bool result = IsExist(board,visited,word,boardRow+1,boardCol,wordIndex+1) 
                || IsExist(board,visited,word,boardRow-1,boardCol,wordIndex+1)
                || IsExist(board,visited,word,boardRow,boardCol+1,wordIndex+1)
                || IsExist(board,visited,word,boardRow,boardCol-1,wordIndex+1);
        //取回该棋子
        visited[boardRow][boardCol] = 0;
        return result;
    }

    public bool Exist(char[][] board, string word) {
        if(board.Length == 0 || board == null || word == ""){
            return false;
        }
        //初始化记录数组
        int[][] visited = new int[board.Length][];
        for(int i=0; i<board.Length; i++){
            visited[i] = new int[board[0].Length];
        }

        bool result = false;
        for(int i = 0; i < board.Length; i++){
            for(int j = 0; j < board[0].Length; j++){
                result = IsExist(board, visited, word,i, j, 0);
                if(result == true){
                    return result;
                }
            }
        }
        return result;
    }
}

实现代码(第二遍)

csharp
public class Solution {
    private bool[,] visited;
    private bool Exist(char[][] board, string word, int i, int j, int index){
        if(index == word.Length){ //已经匹配完所有数字,返回 true
            return true;
        }
        //越界或者不匹配,或者已经放置
        if(i<0 || j<0 || i>=board.Length || j>=board[0].Length || board[i][j] != word[index] || visited[i,j] == true){
            return false;
        }
        //说明可以继续
        //放置
        visited[i,j] = true;
        //判断是否可以继续,只能朝4个方向走
        bool result = Exist(board,word,i,j+1,index+1)
        || Exist(board,word,i,j-1,index+1)
        || Exist(board,word,i+1,j,index+1)
        || Exist(board,word,i-1,j,index+1);
        //取回
        visited[i,j] = false;
        return result;
    }

    public bool Exist(char[][] board, string word) {
        bool result = false;
        visited = new bool[board.Length, board[0].Length];
        for(int i=0; i<board.Length; i++){
            for(int j=0; j<board[0].Length; j++){
                result = result || Exist(board,word,i,j,0);
                if(result){
                    return true;
                }
            }
        }
        return result;
    }
}

实现代码:复习20220503

csharp
public class Solution {


    bool[,] visited;

    public bool Exist(char[][] board, string word) {
        int m = board.Length;
        int n = board[0].Length;
        visited = new bool[m,n];

        //回溯法试探
        //选择任意一个点作为起始
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if(IsExist(board,word,i,j,0)){
                    return true;
                }
            }
        }
        return false;
    }

    private bool IsExist(char[][] board, string word, int i, int j, int wordIndex){
        //放置完
        if(wordIndex == word.Length){
            return true;
        }
        //检查越界 或者占用
        if(i<0 || j<0 || i==board.Length || j==board[0].Length || visited[i,j] || board[i][j] != word[wordIndex]){
            return false;
        }   

        //放置
        visited[i,j] = true;
        //放置其他四个地方
        bool result = IsExist(board,word,i-1,j,wordIndex+1) 
                    ||IsExist(board,word,i+1,j,wordIndex+1) 
                    ||IsExist(board,word,i,j-1,wordIndex+1) 
                    ||IsExist(board,word,i,j+1,wordIndex+1) ;

        //取回
        visited[i,j] = false;
        return result;
    }
}

Released under the MIT License.