【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)

简介: 本文讲解了两道经典的图论问题:**岛屿数量(LeetCode 200)** 和 **腐烂的橘子(LeetCode 994)**,分别通过 DFS/BFS 实现。在“岛屿数量”中,利用深度或广度优先搜索遍历二维网格,标记连通陆地并计数;“腐烂的橘子”则采用多源 BFS,模拟腐烂传播过程,计算最短时间。两者均需掌握访问标记技巧,是学习网格搜索算法的绝佳实践。

🌊 BFS/DFS 实战:岛屿数量 & 腐烂的橘子(LeetCode 200 & 994)

两道图论基础题,涉及 BFS 与 DFS 的应用,主要用于掌握二维网格中遍历与标记访问的技巧:

  • 🏝️ 200. 岛屿数量(Number of Islands)
  • 🍊 994. 腐烂的橘子(Rotting Oranges)

🏝️ 一、200. 岛屿数量

📌 题目描述

给定一个由 '1'(陆地)和 '0'(水)组成的二维网格,计算岛屿的数量。

岛屿总是由相邻的陆地连接组成(水平或垂直),并且被水包围。


💡 解题思路

这道题的核心是:对每一个未被访问的陆地进行一次 DFS 或 BFS,将整块陆地标记为已访问,岛屿数量 +1

✅ 方法一:DFS 深度优先遍历

  • 从每个为 '1' 的位置出发,递归淹没它相邻的陆地;
  • 每次新的 DFS 开始,即发现了一个新的岛屿。
func numIslands(grid [][]byte) int {
   
    m, n := len(grid), len(grid[0])
    var dfs func(int, int)
    dfs = func(i, j int) {
   
        if i < 0 || j < 0 || i >= m || j >= n || grid[i][j] == '0' {
   
            return
        }
        grid[i][j] = '0'
        dfs(i+1, j)
        dfs(i-1, j)
        dfs(i, j+1)
        dfs(i, j-1)
    }

    count := 0
    for i := 0; i < m; i++ {
   
        for j := 0; j < n; j++ {
   
            if grid[i][j] == '1' {
   
                dfs(i, j)
                count++
            }
        }
    }
    return count
}

✅ 方法二:BFS 广度优先遍历

  • 使用队列,每次将 '1' 入队后,通过四个方向将邻接陆地逐个加入队列。

🧠 小结

技术点 说明
核心思想 将一整块陆地用 DFS/BFS 访问并标记
遍历方式 DFS / BFS 均可
时间复杂度 O(m × n)
空间复杂度 DFS:O(m × n)(递归栈),BFS:队列空间

🍊 二、994. 腐烂的橘子

📌 题目描述

在一个二维网格中:

  • 0 代表空单元格,
  • 1 代表新鲜橘子,
  • 2 代表腐烂橘子。

每分钟,所有腐烂橘子会让上下左右相邻的新鲜橘子变腐烂
求腐烂完所有橘子的最短分钟数,如果无法全部腐烂,返回 -1


💡 解题思路

这是标准的多源 BFS 问题,初始队列中包含所有腐烂橘子的位置,然后每轮向周围传播。

✅ 步骤总结:

  1. 初始化队列,将所有腐烂橘子的坐标加入;
  2. 记录新鲜橘子的数量 fresh
  3. 每轮扩散一层(即一分钟),对新鲜橘子变腐烂,fresh--
  4. 最终看 fresh 是否为 0,若是返回分钟数,否则返回 -1。

📦 Go 实现

type pair struct{
    x, y int }

func orangesRotting(grid [][]int) int {
   
    m, n := len(grid), len(grid[0])
    queue := []pair{
   }
    fresh := 0

    for i := 0; i < m; i++ {
   
        for j := 0; j < n; j++ {
   
            if grid[i][j] == 2 {
   
                queue = append(queue, pair{
   i, j})
            } else if grid[i][j] == 1 {
   
                fresh++
            }
        }
    }

    dirs := []pair{
   {
   0, 1}, {
   1, 0}, {
   0, -1}, {
   -1, 0}}
    minutes := 0

    for len(queue) > 0 && fresh > 0 {
   
        size := len(queue)
        for i := 0; i < size; i++ {
   
            curr := queue[0]
            queue = queue[1:]
            for _, d := range dirs {
   
                x, y := curr.x + d.x, curr.y + d.y
                if x >= 0 && y >= 0 && x < m && y < n && grid[x][y] == 1 {
   
                    grid[x][y] = 2
                    fresh--
                    queue = append(queue, pair{
   x, y})
                }
            }
        }
        minutes++
    }

    if fresh > 0 {
   
        return -1
    }
    return minutes
}

⚠️ 注意事项

  • 初始化时要统计新鲜橘子的数量
  • 每一轮是批量扩散(多源 BFS)
  • 不能单独计数某个腐烂橘子的时间,要整体一起推进。

🔚 总结对比

特性 岛屿数量(200) 腐烂的橘子(994)
模型 连通块计数 最短传播路径,多源 BFS
算法 DFS / BFS BFS(层级扩散)
是否需要标记访问
特别关注 连通性与计数 初始状态和时间控制

目录
相关文章
|
4月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
8月前
|
Go
【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)
本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!
350 1
|
8月前
|
Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本篇博客详细解析了三道经典的动态规划问题:198. 打家劫舍(线性状态转移)、279. 完全平方数与322. 零钱兑换(完全背包问题)。通过 Go 语言实现,帮助读者掌握动态规划的核心思想及其实战技巧。从状态定义到转移方程,逐步剖析每道题的解法,并总结其异同点,助力解决更复杂的 DP 问题。适合初学者深入理解动态规划的应用场景和优化方法。
284 0
|
4月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
289 3
|
12月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
12月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
6月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
404 1
|
6月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
480 0
|
6月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
321 0
|
6月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
353 0