(leetcode)力扣100 60单词搜索(回溯)

题目

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

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

数据范围

m == board.length

n = board[i].length

1 <= m, n <= 6

1 <= word.length<= 15

board 和 word 仅由大小写英文字母组成

测试用例

示例1

java 复制代码
输入:board = [['A','B','C','E'],['S','F','C','S'],['A','D','E','E']], word = "ABCCED"
输出:true

示例2

java 复制代码
输入:board = [['A','B','C','E'],['S','F','C','S'],['A','D','E','E']], word = "SEE"
输出:true

示例3

java 复制代码
输入:board = [['A','B','C','E'],['S','F','C','S'],['A','D','E','E']], word = "ABCB"
输出:false

题解1(博主版本,时间ONM*3L

java 复制代码
class Solution {
    // 全局变量记录最终结果,只要找到一条路径就变为 true
    boolean res = false;
    // 定义四个移动方向:右、左、下、上 (注意:这里的顺序和坐标对应关系视具体定义而定)
    int move[][] = {{0, 1, 0, -1}, {1, 0, -1, 0}};
    // 辅助数组,用于记录网格是否被访问过 (Memory/Visited)
    int mry[][];
    // c 代表行数 (count/rows), r 代表列数 (rows/columns) - *注:命名有点反直觉*
    int c, r;

    public boolean exist(char[][] board, String word) {
        char w[] = word.toCharArray();
        char head = w[0];
        
        c = board.length;     // 获取行数
        r = board[0].length;  // 获取列数

        // 遍历整个棋盘寻找起点
        for(int i = 0; i < c; i++){
            for(int j = 0; j < r; j++){
                // 只有当当前字符等于单词首字母时,才开始搜索
                if(board[i][j] == head){
                    // 初始化访问数组 (注意:这里每次匹配头字符都new一次数组,开销较大)
                    mry = new int[c][r];
                    mry[i][j] = 1; // 标记起点已访问
                    
                    // 开始 DFS,参数:当前的二维坐标被压缩成了一维 (i*r+j)
                    dfs(board, w, mry, 1, i * r + j);
                    
                    // 如果在 DFS 中找到了路径,直接返回 true
                    if(res){
                        return res;
                    }
                }
            }
        }

        return false; // 遍历完都没找到
    }

    // DFS 递归函数
    // stage: 当前匹配到了单词的第几个字符
    // curr: 当前坐标的一维表示
    public void dfs(char[][] board, char[] word, int mry[][], int stage, int curr){
        // 递归终止条件:如果匹配长度等于单词长度,说明找到了
        if(stage == word.length){
            res = true;
            return;
        }
        
        // 将一维坐标还原回二维坐标 x, y
        int x = curr / r;
        int y = curr % r;
        
        // 尝试向四个方向移动
        for(int k = 0; k < 4; k++){
            // 剪枝:如果已经找到了结果,不需要继续搜索
            if(res == true){
                return;
            }
            
            // 计算下一个坐标
            int tx = x + move[0][k];
            int ty = y + move[1][k];
            
            // 边界检查 && 检查是否已访问 && 检查字符是否匹配
            if(tx >= 0 && tx < c && ty >= 0 && ty < r && 
               mry[tx][ty] != 1 && board[tx][ty] == word[stage]){
                
                mry[tx][ty] = 1; // 标记访问
                
                // 递归进入下一层
                dfs(board, word, mry, stage + 1, tx * r + ty);
                
                mry[tx][ty] = 0; // 回溯:恢复状态,以便其他路径可以使用该格子
            }
        }
    }
}

官解(时空同上)

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)) {
            return false;
        } else if (k == s.length() - 1) {
            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);
                    if (flag) {
                        result = true;
                        break;
                    }
                }
            }
        }
        visited[i][j] = false;
        return result;
    }
}

题解3(题解1优化,使用原始数组 ,时间相同,空间OL)

java 复制代码
class Solution {
    public boolean exist(char[][] board, String word) {
        int m = board.length;
        int n = board[0].length;
        char[] w = word.toCharArray();

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 如果找到入口,直接开始 DFS
                if (dfs(board, w, i, j, 0)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        // 1. 终止条件:如果不匹配,或者越界
        if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || board[i][j] != word[k]) {
            return false;
        }
        
        // 2. 成功条件:匹配到了最后一个字符
        if (k == word.length - 1) {
            return true;
        }

        // 3. 标记当前格子已访问(用特殊字符覆盖,省去 mry 数组)
        char temp = board[i][j];
        board[i][j] = '#'; 

        // 4. 向四个方向递归
        boolean found = dfs(board, word, i + 1, j, k + 1) ||
                        dfs(board, word, i - 1, j, k + 1) ||
                        dfs(board, word, i, j + 1, k + 1) ||
                        dfs(board, word, i, j - 1, k + 1);

        // 5. 回溯:还原当前格子
        board[i][j] = temp;

        return found;
    }
}

思路

这道题的思路大差不差都是回溯算法,但具体实现有点差别,题解1大家看个乐就好不要学,虽然与官解时空一样,但终究差一些,因为每次都创建了一个新的mry,这对于回溯算法是不需要的,按官解的回溯还原就行了,博主没有直接传xy,传的是组合信息,这里纯是博主想写写这个代码了,实际效果不如直接传xy,因为需要做一次计算。

但前两种方法都还没有做到完全信任回溯法,只要我们定一个临时变量存储当前格子的值,我们就可以用回溯法还原,记录操作就可以在原数组中完成。

相关推荐
卖报的大地主2 小时前
强化学习在图像生成中的应用:范式演进、算法机制与前沿展望
算法
圣保罗的大教堂2 小时前
leetcode 3637. 三段式数组 I 简单
leetcode
ʚB҉L҉A҉C҉K҉.҉基҉德҉^҉大2 小时前
C++中的策略模式进阶
开发语言·c++·算法
June bug2 小时前
【PMP】项目生命周期与组织变革
职场和发展·学习方法
June bug2 小时前
【PMP】风险管理
经验分享·职场和发展·学习方法
weixin_445402302 小时前
模板元编程应用场景
开发语言·c++·算法
啊阿狸不会拉杆2 小时前
《机器学习导论》第 1 章 - 引言
人工智能·python·算法·机器学习·ai·numpy·matplotlib
轻轻唱2 小时前
2026专业PPT设计服务商推荐:TOP10深度评测与选择指南
大数据·人工智能·算法
s1hiyu2 小时前
嵌入式C++低功耗设计
开发语言·c++·算法