LeetCode79:单词搜索DFS回溯详解

题目LeetCode 79

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

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

示例:

输入: board = [['A','B','C','E'],['S','F','C','S'],['A','D','E','E']], word = "ABCCED"
**输出:**true

Python解法

代码示例(回溯+DFS)

python 复制代码
from typing import List
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:

        m = len(board)
        n = len(board[0])
        dirs = [(-1, 0), (1, 0), (0, -1), (0, 1)]

        def dfs(i , j, k):
            if board[i][j] != word[k]:
                return False
            if k == len(word) - 1:
                return True

            temp = board[i][j]
            board[i][j] = '#'
            for dx, dy in dirs:
                x = i + dx
                y = j + dy
                if 0<=x<m and 0<=y<n:
                    if dfs(x, y, k + 1):
                        return True
            board[i][j] = temp
            return False

        for i in range(m):
            for j in range(n):
                if dfs(i, j, 0):
                    return True
        return False

解释

1, 首先测长度,设置移动方向

python 复制代码
m = len(board)
n = len(board[0])
        
# 上下左右
dirs = [(-1,0), (1,0), (0,-1), (0,1)]

2, 然后是主要函数,首先判断不匹配与匹配成功

python 复制代码
# 1. 字符不匹配,直接返回
if board[i][j] != word[k]:
    return False
# 2. 已经匹配到最后一个字母,成功
if k == len(word) - 1:
    return True

3, 标记走过的,避免回头

举个例子

你现在走的路径是:A → B → C

你走到 B 的时候,**必须把 B 改成 #**不然会发生这种事:

A ← B → C

python 复制代码
temp = board[i][j]   # 先把原来的字母存起来
board[i][j] = '#'   # 把当前格子改成 # ------ 这就是【标记】

4,每个方向都试一试,不越界才往下进行,如果成功直接返回True

python 复制代码
# 四个方向走一走
for dx, dy in dirs:
    x = i + dx
    y = j + dy
    if 0 <= x < m and 0 <= y < n:
        if dfs(x, y, k + 1):
            return True  # 找到就直接返回

5, 恢复原样

为什么要恢复?因为你这条路走不通,不代表别的路不能用这个格子!

看例子:你现在走:A → B → X(走不通)

你退回来的时候,必须把 B 恢复成 B不然别人想走:C → B → D就走不了了,因为 B 被你改成 # 废掉了。

python 复制代码
board[i][j] = tmp  # 把 # 改回原来的字母 ------ 这就是【恢复】

6,将从格子里的各个部分都当一次起点

python 复制代码
# 每个格子都当起点试一次
for i in range(m):
    for j in range(n):
        if dfs(i, j, 0):
            return True

过程演示

Java解法(回溯+DFS)

java 复制代码
import java.util.*;

class Solution {
    public boolean exist(char[][] board, String word) {
        // 行列 定义在 public 里面
        int m = board.length;
        int n = board[0].length;
        
        // 四个方向 定义在 public 里面
        int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

        // 遍历每个起点
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (dfs(board, word, i, j, 0, m, n, dirs)) {
                    return true;
                }
            }
        }
        return false;
    }

    // DFS 递归函数
    private boolean dfs(char[][] board, String word, int i, int j, int k, 
                        int m, int n, int[][] dirs) {
        // 字符不匹配直接返回
        if (board[i][j] != word.charAt(k)) {
            return false;
        }
        // 匹配到最后一位,成功
        if (k == word.length() - 1) {
            return true;
        }

        // 标记已访问
        char temp = board[i][j];
        board[i][j] = '#';

        // 四个方向搜索
        for (int[] dir : dirs) {
            int x = i + dir[0];
            int y = j + dir[1];
            if (x >= 0 && x < m && y >= 0 && y < n) {
                if (dfs(board, word, x, y, k + 1, m, n, dirs)) {
                    return true;
                }
            }
        }

        // 回溯恢复
        board[i][j] = temp;
        return false;
    }
}

C++解法(回溯+DFS)

cpp 复制代码
#include <vector>
#include <string>
using namespace std;

class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        int m = board.size();          // C++ 用 .size()
        int n = board[0].size();
        
        // 四个方向:上下左右
        vector<vector<int>> dirs = {{-1,0}, {1,0}, {0,-1}, {0,1}};

        // 遍历每个起点
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (dfs(board, word, i, j, 0, m, n, dirs)) {
                    return true;
                }
            }
        }
        return false;
    }

private:
    bool dfs(vector<vector<char>>& board, string word, int i, int j, int k,
            int m, int n, vector<vector<int>>& dirs) {
        
        // 字符不匹配直接返回
        if (board[i][j] != word[k]) {  // C++ string 可以直接用 []
            return false;
        }

        // 匹配到最后一位,成功
        if (k == word.size() - 1) {
            return true;
        }

        // 标记已访问
        char temp = board[i][j];
        board[i][j] = '#';

        // 四个方向搜索
        for (auto& dir : dirs) {       // C++ 增强for循环
            int x = i + dir[0];
            int y = j + dir[1];
            if (x >= 0 && x < m && y >= 0 && y < n) {
                if (dfs(board, word, x, y, k+1, m, n, dirs)) {
                    return true;
                }
            }
        }

        // 回溯恢复
        board[i][j] = temp;
        return false;
    }
};
相关推荐
kkkAloha4 小时前
Python
python
skywalk81634 小时前
下载安装 Temurin® JDK JDK 21 - LTS 速度很慢,有办法加速吗?
java·开发语言
Kiling_07044 小时前
Java方法引用与排序算法精讲
开发语言·python
Mr数据杨5 小时前
【Codex】用PPT文案额外描述优化课件生成细节
java·javascript·django·powerpoint·codex·项目开发
纪伊路上盛名在5 小时前
聊一聊关于gene的富集分析
算法·数据分析·统计分析·计算生物·gene
xyq20245 小时前
AppML 案例未来:探索移动应用机器学习的新篇章
开发语言
Mr.朱鹏5 小时前
5.LangChain零基础速通-LCEL链式调用
python·langchain·django·大模型·llm·virtualenv
Andya_net5 小时前
AI | CC GUI 集成 IDEA 完整教程
java·人工智能·intellij-idea
MZ_ZXD0015 小时前
springboot音乐播放器系统-计算机毕业设计源码76317
java·c语言·c++·spring boot·python·flask·php