跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言算法

递归、搜索与回溯算法及 FloodFill 算法详解

深入讲解了递归、搜索与回溯算法在二维矩阵中的应用,重点剖析了 FloodFill 算法及其变体。内容涵盖图像渲染、岛屿数量、岛屿最大面积、被围绕的区域、太平洋大西洋水流问题、扫雷游戏以及机器人的运动范围等经典 LeetCode 题目。文章详细阐述了深度优先搜索 (DFS) 的核心逻辑,包括连通区域标记、边界处理、逆向思维优化(如正难则反策略)、以及何时需要恢复现场等关键细节,并提供了完整的 Python 代码实现与注意事项总结。

忘忧发布于 2026/2/7更新于 2026/7/21816 浏览
递归、搜索与回溯算法及 FloodFill 算法详解

递归、搜索与回溯算法及 FloodFill 算法详解

图像渲染 (LeetCode 733)

题目解析

给定一个二维整数数组 image,表示图像的像素值。给定起始坐标 (sr, sc) 和新颜色 newColor。从起始点开始,将相连的相同颜色的区域填充为新颜色。

算法原理

使用深度优先搜索 (DFS) 或广度优先搜索 (BFS) 遍历连通区域。核心是判断当前像素颜色是否与起始点颜色一致且未被访问过。

解法:暴搜 (DFS)

处理细节问题

如果原始像素值和要修改像素值相同 (image[sr][sc] == color),直接返回即可,避免无限递归。

代码实现
def floodFill(image, sr, sc, newColor):
    original_color = image[sr][sc]
    if original_color == newColor:
        return image
    
    rows, cols = len(image), len(image[0])
    directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
    
    def dfs(r, c):
        if image[r][c] == original_color:
            image[r][c] = newColor
            for dr, dc in directions:
                nr, nc = r + dr, c + dc
                if 0 <= nr < rows and 0 <= nc < cols:
                    dfs(nr, nc)
    
    dfs(sr, sc)
    return image

注意: 本题不需要额外的 vis 数组标记走过的格子,因为修改后的颜色不再是 original_color,会被剪枝条件筛查掉。


岛屿数量 (LeetCode 200)

题目解析

给定由 '1'(陆地) 和 '0'(水) 组成的二维网格,计算岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

算法原理

遍历网格,遇到 '1' 时岛屿计数加一,并使用 DFS 将该岛屿所有相连的 '1' 标记为已访问(例如改为 '0')。

解法:深度优先遍历

处理细节问题
  • 剪枝条件:grid[x][y] == '1',注意字符类型。
  • ret++ 设置位置:在发现新岛屿起点时增加,而不是在每个格子查找完后。
代码实现
def numIslands(grid):
    if not grid:
        return 0
    
    rows, cols = len(grid), len(grid[0])
    count = 0
    
    def dfs(r, c):
        if r < 0 or c < 0 or r >= rows or c >= cols or grid[r][c] != '1':
            return
        grid[r][c] = '0'  # 标记为已访问
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        for dr, dc in directions:
            dfs(r + dr, c + dc)
    
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == '1':
                count += 1
                dfs(i, j)
    
    return count

思考: 为什么这道题不用恢复现场? 因为我们要找出一块矩阵所有的联通区,这些联通区需要被记录(通过改变状态),且各个联通区不会出现重叠,所以在回溯时不需要也不能把记录过的联通区还原。


岛屿的最大面积 (LeetCode 695)

题目解析

同上题,但需要计算最大岛屿的面积。

算法原理

在 DFS 过程中累加当前连通区域的面积,并更新全局最大值。

代码实现

def maxAreaOfIsland(grid):
    if not grid:
        return 0
    
    rows, cols = len(grid), len(grid[0])
    max_area = 0
    
    def dfs(r, c):
        if r < 0 or c < 0 or r >= rows or c >= cols or grid[r][c] != 1:
            return 0
        grid[r][c] = 0  # 标记访问
        area = 1
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        for dr, dc in directions:
            area += dfs(r + dr, c + dc)
        return area
    
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 1:
                current_area = dfs(i, j)
                max_area = max(max_area, current_area)
    
    return max_area

注意: count 不应设置为 dfs 的参数,否则回溯时会丢失部分统计结果,应作为局部变量返回累加值。


被围绕的区域 (LeetCode 130)

题目解析

给定一个二维矩阵,包含 'X' 和 'O',将所有被 'X' 围绕的 'O' 替换为 'X'。

算法原理

正难则反。直接寻找被包围的区域较难,不如先找出与边界相连的 'O',这些区域不会被包围。剩下的 'O' 即为被包围区域。

解法:反向标记

  1. 扫描四条边,若遇到 'O',从该点开始 DFS/BFS 标记所有连通的 'O'(例如改为 'A')。
  2. 遍历整个矩阵,将剩余的 'O' 改为 'X',将 'A' 改回 'O'。
代码实现
def solve(board):
    if not board:
        return
    
    rows, cols = len(board), len(board[0])
    
    def dfs(r, c):
        if r < 0 or c < 0 or r >= rows or c >= cols or board[r][c] != 'O':
            return
        board[r][c] = 'A'
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        for dr, dc in directions:
            dfs(r + dr, c + dc)
    
    # 标记边缘的 O
    for i in range(rows):
        dfs(i, 0)
        dfs(i, cols - 1)
    for j in range(cols):
        dfs(0, j)
        dfs(rows - 1, j)
    
    # 翻转剩余
    for i in range(rows):
        for j in range(cols):
            if board[i][j] == 'O':
                board[i][j] = 'X'
            elif board[i][j] == 'A':
                board[i][j] = 'O'

太平洋大西洋水流问题 (LeetCode 417)

题目解析

给定一个 m x n 的非负整数矩阵,表示高度。水可以从高流向低或等高。找出既能流向太平洋(左/上边界)又能流向大西洋(右/下边界)的单元格。

算法原理

正难则反。从海洋边界逆着水流向上游搜索(从低到高)。分别找出能到达太平洋的所有点和能到达大西洋的所有点,取交集。

代码实现

def pacificAtlantic(heights):
    if not heights:
        return []
    
    rows, cols = len(heights), len(heights[0])
    pacific = set()
    atlantic = set()
    
    def dfs(r, c, visited):
        visited.add((r, c))
        for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
            nr, nc = r + dr, c + dc
            if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in visited:
                if heights[nr][nc] >= heights[r][c]:
                    dfs(nr, nc, visited)
    
    # 从太平洋边界开始
    for i in range(rows):
        dfs(i, 0, pacific)
        dfs(i, cols - 1, atlantic)
    for j in range(cols):
        dfs(0, j, pacific)
        dfs(rows - 1, j, atlantic)
    
    return list(pacific & atlantic)

扫雷游戏 (LeetCode 529)

题目解析

根据点击位置揭示盘面。如果是地雷显示 'X';如果是空格,显示周围地雷数;如果是空白且周围无雷,递归揭示周围 8 个格子。

算法原理

模拟游戏规则。使用 DFS 递归展开空白区域。注意八方向连通。

代码实现

def updateBoard(board, click):
    r, c = click
    if board[r][c] == 'M':
        board[r][c] = 'X'
        return board
    
    rows, cols = len(board), len(board[0])
    directions = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i != 0 or j != 0]
    
    def dfs(r, c):
        mine_count = 0
        for dr, dc in directions:
            nr, nc = r + dr, c + dc
            if 0 <= nr < rows and 0 <= nc < cols and board[nr][nc] == 'M':
                mine_count += 1
        
        if mine_count > 0:
            board[r][c] = str(mine_count)
        else:
            board[r][c] = 'B'
            for dr, dc in directions:
                nr, nc = r + dr, c + dc
                if 0 <= nr < rows and 0 <= nc < cols and board[nr][nc] == 'E':
                    dfs(nr, nc)
    
    dfs(r, c)
    return board

机器人的运动范围 (LeetCode 剑指 Offer 13)

题目解析

地上有一个 m 行 n 列的方格。机器人从 [0,0] 开始移动,每次向左、右、上、下移动一格。不能进入行坐标和列坐标的数位之和大于 k 的格子。

算法原理

深度优先遍历。定义辅助函数计算数位之和。使用 visited 数组防止重复统计。

代码实现

def movingCount(m, n, k):
    def digit_sum(num):
        s = 0
        while num > 0:
            s += num % 10
            num //= 10
        return s
    
    visited = [[False] * n for _ in range(m)]
    
    def dfs(r, c):
        if r < 0 or c < 0 or r >= m or c >= n or visited[r][c]:
            return 0
        if digit_sum(r) + digit_sum(c) > k:
            return 0
        
        visited[r][c] = True
        return 1 + dfs(r + 1, c) + dfs(r - 1, c) + dfs(r, c + 1) + dfs(r, c - 1)
    
    return dfs(0, 0)

注意: 必须定义标记数组,否则 ret 会统计重复走过的格子和递归回溯经过的格子的总数。

目录

  1. 递归、搜索与回溯算法及 FloodFill 算法详解
  2. 图像渲染 (LeetCode 733)
  3. 题目解析
  4. 算法原理
  5. 解法:暴搜 (DFS)
  6. 处理细节问题
  7. 代码实现
  8. 岛屿数量 (LeetCode 200)
  9. 题目解析
  10. 算法原理
  11. 解法:深度优先遍历
  12. 处理细节问题
  13. 代码实现
  14. 岛屿的最大面积 (LeetCode 695)
  15. 题目解析
  16. 算法原理
  17. 代码实现
  18. 被围绕的区域 (LeetCode 130)
  19. 题目解析
  20. 算法原理
  21. 解法:反向标记
  22. 代码实现
  23. 太平洋大西洋水流问题 (LeetCode 417)
  24. 题目解析
  25. 算法原理
  26. 代码实现
  27. 扫雷游戏 (LeetCode 529)
  28. 题目解析
  29. 算法原理
  30. 代码实现
  31. 机器人的运动范围 (LeetCode 剑指 Offer 13)
  32. 题目解析
  33. 算法原理
  34. 代码实现
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 6 款免费 AI 写作软件测评:辅助网文创作工具对比
  • JavaWeb 数据交换与异步请求:JSON 与 Ajax 技术详解
  • 零基础入门网络安全与 Web 安全学习路线指南
  • 基于 OpenClaw 与 Claude 构建自动化写作工作流实践
  • 行星减速器:结构原理、计算与 C++ 实现
  • DeepSeek 本地化部署实测:ToDesk、顺网云与海马云性能对比
  • 国产数据库新机遇:电科金仓融合技术与 AI 化演进
  • 2024 年 AI 绘画现状分析:Midjourney 与 Stable Diffusion 实用价值探讨
  • 腾讯 RecSys'24:基于行为微调 LLM 初始化物品 Embedding 的高效推荐方法
  • Eino 组件核心:Retriever 统一 RAG 检索协议
  • RAG 入门教程:LangChain 框架 v0.2 介绍
  • Mac M 系列芯片适配:mlc-llm 与 llama.cpp 对比
  • Spring Boot Web 三大核心交互实战:表单、AJAX 与 JSON
  • Unreal Engine 4.27 结合 AirSim 搭建澳洲农村无人机仿真环境
  • 2025 AI 技术成长复盘与深度学习实践心得
  • 前端虚拟列表原理深度解析与实战实现
  • 大模型、AI 大模型与 GPT 模型详解
  • AI 时代:为何‘人人都是产品经理’成为现实
  • AutoGPT 结合 Python 构建自主 AI 智能体实战指南
  • Linux vi/vim 编辑器基础使用指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online