leetcode 项目精讲:Swim in Rising Water(水位上升泳池)五类解法与最小化路径最大值的图论建模
leetcode 项目精讲Swim in Rising Water水位上升泳池五类解法与最小化路径最大值的图论建模【免费下载链接】leetcodeLeetcode solutions项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode本篇技术指南围绕 LeetCode 经典题778. Swim in Rising Water水位上升的泳池中游泳展开以本仓库 hints/swim-in-rising-water.md 的解题提示为骨架系统讲解从暴力 DFS 到 Dijkstra、Kruskal 的完整解法演进。读者学完后将掌握最小化路径上的最大值这类 minimax 路径问题的建模思路并能独立用贪心堆、二分答案、并查集等策略写出多语言实现。1. 问题定义与核心洞察给定一个n x n的整数矩阵gridgrid[i][j]表示坐标(i, j)处的地势高度。雨水落下后在时刻t整个网格的水深均为t。你从左上角(0, 0)出发目标是到达右下角(n-1, n-1)并且只有当两个相邻格子的高度都不超过t时才能游过去游泳本身不消耗时间但你可能需要在水位上涨到足够高之前原地等待。需要返回的是能够从起点游到终点的最小等待时间。1.1 把矩阵看成图正如 hints/swim-in-rising-water.md 的 Hint 1 所指出的把每个格子视为一个节点相邻格子之间连边。当水位为t时只有高度 t的格子才是开放的路径只能穿过这些开放格子。1.2 关键洞察路径成本 路径上的最大高度Hint 1 和 Hint 2 给出了本题最核心的观察一条路径所花费的时间由该路径上所有格子的最大高度值决定。因为你必须等水位涨到这条路上最高的那个格子那么高才能通行。因此问题被等价转化为找到一条从(0, 0)到(n-1, n-1)的路径使得路径上格子的最大高度最小。这就是典型的minimax极小化极大路径问题——标准最短路径算法如 Dijkstra在这里依然适用只是距离的定义从边权之和变成了路径上的最大边权。1.3 复杂度目标根据 hints/swim-in-rising-water.md 的 Recommended Time Space Complexity指标目标时间复杂度O(n² log n)空间复杂度O(n²)其中n是方阵的行列数。下面的 Dijkstra 与 Kruskal 方案正好达到该标准。2. 方案一暴力 DFSBrute Force直觉暴力枚举从起点到终点的每一条可行路径。对每条路径维护一个截至目前踩过的最大高度t到达终点时返回该值对所有路径取最小值即为答案。算法步骤从(0, 0)出发初始时间t 0对单元格(r, c)越界或已访问 → 返回一个很大的数无效路径更新t max(t, grid[r][c])站在该格所需的水位若是终点(n-1, n-1)→ 返回t标记(r, c)为已访问递归尝试上、下、左、右四个方向取四个递归结果的最小值从当前位置出发的最佳路径回溯取消标记返回该最小值。Python 实现class Solution: def swimInWater(self, grid: List[List[int]]) - int: n len(grid) visit [[False] * n for _ in range(n)] def dfs(node, t): r, c node if min(r, c) 0 or max(r, c) n or visit[r][c]: return 1000000 if r (n - 1) and c (n - 1): return max(t, grid[r][c]) visit[r][c] True t max(t, grid[r][c]) res min(dfs((r 1, c), t), dfs((r - 1, c), t), dfs((r, c 1), t), dfs((r, c - 1), t)) visit[r][c] False return res return dfs((0, 0), 0)仓库同款实现可参考 python/0778-swim-in-rising-water.py该文件内为下文方案四 Dijkstra 的实现暴力 DFS 的多语言版本见 articles/swim-in-rising-water.md 第一节Java/C/JavaScript/C#/Go/Kotlin/Swift/Rust 均有。复杂度时间O(4^(n²))—— 路径数量随格子数指数爆炸仅用于理解问题空间O(n²)—— visited 矩阵与递归栈。3. 方案二DFS 水位线性扫描直觉把问题改写成yes/no 判定问题如果水位是t我能不能从(0, 0)游到(n-1, n-1)水位为t时只允许踩grid[r][c] t的格子。于是从最小的可能高度开始逐一把t加 1返回第一个能到达终点的t。算法步骤计算网格最小值minH与最大值maxH定义canReach(t)从(0,0)做 DFS禁止进入越界、已访问、或高度 t的格子能到达(n-1, n-1)即返回true令t从minH遍历到maxH第一个canReach(t) true的t即为答案每次尝试后必须重置 visited。Python 实现class Solution: def swimInWater(self, grid: List[List[int]]) - int: n len(grid) visit [[False] * n for _ in range(n)] minH maxH grid[0][0] for row in range(n): maxH max(maxH, max(grid[row])) minH min(minH, min(grid[row])) def dfs(node, t): r, c node if (min(r, c) 0 or max(r, c) n or visit[r][c] or grid[r][c] t): return False if r (n - 1) and c (n - 1): return True visit[r][c] True return (dfs((r 1, c), t) or dfs((r - 1, c), t) or dfs((r, c 1), t) or dfs((r, c - 1), t)) for t in range(minH, maxH): if dfs((0, 0), t): return t for r in range(n): for c in range(n): visit[r][c] False return maxH复杂度时间O(n⁴)—— 最多尝试O(n²)个水位每个水位一次O(n²)的 DFS空间O(n²)。4. 方案三二分答案 DFSBinary Search DFS直觉canReach(t)具有单调性这是二分答案成立的前提如果水位t能到达终点那么任何更高的水位t1, t2, ...也一定能到达开放的格子只会更多如果水位t不能到达那么任何更低的水位也不能。因此可以对答案t做二分搜索每次用 DFS 验证当前mid是否可行。算法步骤搜索范围low 网格最小值high 网格最大值定义canReach(t)DFS 只走高度 t的格子逻辑与方案二相同二分mid (low high) // 2若canReach(mid)为真 → 尝试更小水位high mid否则 → 需要更多水low mid 1每次验证前后重置 visited当low high时即为最小所需时间。Python 实现class Solution: def swimInWater(self, grid: List[List[int]]) - int: n len(grid) visit [[False] * n for _ in range(n)] minH maxH grid[0][0] for row in range(n): maxH max(maxH, max(grid[row])) minH min(minH, min(grid[row])) def dfs(node, t): r, c node if (min(r, c) 0 or max(r, c) n or visit[r][c] or grid[r][c] t): return False if r (n - 1) and c (n - 1): return True visit[r][c] True return (dfs((r 1, c), t) or dfs((r - 1, c), t) or dfs((r, c 1), t) or dfs((r, c - 1), t)) l, r minH, maxH while l r: m (l r) 1 if dfs((0, 0), m): r m else: l m 1 for row in range(n): for col in range(n): visit[row][col] False return r复杂度时间O(n² log n)—— 二分次数O(log n)每次 DFSO(n²)空间O(n²)。5. 方案四Dijkstra 算法推荐达成 Hint 3 的目标复杂度直觉Hint 3 明确指出用 Dijkstra 算法。初始化一个最小堆和一张无穷大矩阵从源点(0, 0)开始运行沿路径记录遇到的最大高度并以此作为 Dijkstra 比较的键一旦弹出终点(n-1, n-1)即返回到达该点的路径上的最大高度。把每个格子的高度理解为允许你站在上面的最早时刻。从起点到终点的路径总时间不是求和而是路径上踩过的最大高度。于是 Dijkstra 的定义变为到达某格子的成本 迄今为止路径上最小的最大高度。算法步骤用最小堆存状态(timeSoFar, r, c)其中timeSoFar 到达(r, c)的路径最大高度初始入堆(grid[0][0], 0, 0)循环弹出timeSoFar最小的状态若到达终点直接返回timeSoFar最小堆保证这是最优值对四个邻居若合法且未访问计算newTime max(timeSoFar, grid[nr][nc])并入堆用visited集合保证每个格子只在最优 timeSoFar下被处理一次。Python 实现仓库 python/0778-swim-in-rising-water.py 提供了与本方案完全一致的可运行实现class Solution: def swimInWater(self, grid: List[List[int]]) - int: N len(grid) visit set() minH [[grid[0][0], 0, 0]] # (time/max-height, r, c) directions [[0, 1], [0, -1], [1, 0], [-1, 0]] visit.add((0, 0)) while minH: t, r, c heapq.heappop(minH) if r N - 1 and c N - 1: return t for dr, dc in directions: neiR, neiC r dr, c dc if ( neiR 0 or neiC 0 or neiR N or neiC N or (neiR, neiC) in visit ): continue visit.add((neiR, neiC)) heapq.heappush(minH, [max(t, grid[neiR][neiC]), neiR, neiC])仓库中的多语言佐证Ccpp/0778-swim-in-rising-water.cpp 使用priority_queue实现并对n 1的边界直接返回0同时以max(grid[0][0], grid[n-1][n-1])作为初始结果Javajava/0778-swim-in-rising-water.java 同样在len 1时返回0用PriorityQueueInteger[]按高度排序TypeScripttypescript/0778-swim-in-rising-water.ts 使用MinPriorityQueue入堆时即计算Math.max(grid[nr][nc], weight)Rustrust/0778-swim-in-rising-water.rs 通过自定义State的Ord反转比较实现最小堆完成同样的贪心扩展Go、C#、Kotlin、Swift 版本见 articles/swim-in-rising-water.md 第四节。复杂度时间O(n² log n)空间O(n²)。6. 方案五Kruskal 风格 并查集Union-Find / DSU直觉水位t随时间上涨时刻t只允许踩高度 t的格子因此随着t增大越来越多的格子开放相邻开放格子聚成越来越大的连通区域。我们要求的是起点(0,0)与终点(N-1,N-1)第一次处于同一连通分量的那个最早时刻t。并查集DSU非常适合它能快速合并相邻的开放格子并随时检查起点与终点是否连通。算法步骤Kruskal 式把所有格子整理为(height, r, c)并按height升序排序初始化N*N个节点的 DSU节点编号id r*N c按高度从小到大依次处理每个格子当前格子(r, c)在时刻t height变为开放对四个邻居若邻居高度 t已开放或同时开放执行union每次 union 后检查起点0与终点N*N-1是否连通首次连通时的t即为答案返回该t。Python 实现class DSU: def __init__(self, n): self.Parent list(range(n 1)) self.Size [1] * (n 1) def find(self, node): if self.Parent[node] ! node: self.Parent[node] self.find(self.Parent[node]) return self.Parent[node] def union(self, u, v): pu self.find(u) pv self.find(v) if pu pv: return False if self.Size[pu] self.Size[pv]: pu, pv pv, pu self.Size[pu] self.Size[pv] self.Parent[pv] pu return True def connected(self, u, v): return self.find(u) self.find(v) class Solution: def swimInWater(self, grid: List[List[int]]) - int: N len(grid) dsu DSU(N * N) positions sorted((grid[r][c], r, c) for r in range(N) for c in range(N)) directions [(0, 1), (1, 0), (0, -1), (-1, 0)] for t, r, c in positions: for dr, dc in directions: nr, nc r dr, c dc if 0 nr N and 0 nc N and grid[nr][nc] t: dsu.union(r * N c, nr * N nc) if dsu.connected(0, N * N - 1): return t复杂度时间O(n² log n)—— 排序O(n² log n)路径压缩 按大小合并的 union 近似常数空间O(n²)。7. 常见陷阱Common Pitfallsarticles/swim-in-rising-water.md 末尾总结了本仓库解法中反复出现的五类易错点值得单独强调7.1 把时间误当成步数本题的时间不是路径长度而是等待水位上升到路径最大高度所需的时间。步数再多只要最大高度小时间就短反之亦然。7.2 忘记计入起点和终点答案至少是max(grid[0][0], grid[n-1][n-1])因为你必须能站在两个端点上。仓库 C/Java 实现以max(grid[0][0], grid[n-1][n-1])初始化结果正是对这一点的工程化处理。7.3 二分搜索边界设置错误二分下界应取网格最小值或至少grid[0][0]上界取网格最大值。用0到n*n-1虽然可行但精度更差、区间更大。7.4 多次搜索之间忘记重置 visited在线性扫描与二分两种 DFS 方案中每次用新阈值t做 DFS 前都必须清空visited否则上一次搜索的残留状态会导致错误结果。7.5 并查集节点编号错误Kruskal 方案中最常见的 bug 是 2D 坐标转 1D 索引不一致。必须统一使用r * N c并且只对已开放高度 当前时刻的邻居执行 union。8. 五类解法速查对比方案核心思想时间复杂度空间复杂度适用场景暴力 DFS枚举所有路径取最小最大高度O(4^(n²))O(n²)仅用于理解题意DFS 线性扫描判定式 逐水位尝试O(n⁴)O(n²)小规模数据、演示单调性二分答案 DFS二分水位 DFS 判定O(n² log n)O(n²)面试高频写法Dijkstra最小堆minimax 最短路径O(n² log n)O(n²)推荐实现直观易写Kruskal DSU按高度排序并逐步合并连通分量O(n² log n)O(n²)加深并查集与最小生成树理解延伸思考该题的本质是**最小瓶颈路径minimax path**问题任意两点间最小化最大边权的路径可以由最小生成树MST上的唯一路径给出这正是 Kruskal 解法正确的理论依据同样的建模方式可迁移到最大化最小边权最小化最大海拔差如 Path With Minimum Effort等题目只需调整堆中的比较键与转移公式仓库的完整多语言解法、逐步骤算法说明与复杂度分析可继续阅读 articles/swim-in-rising-water.md并对照 cpp/0778-swim-in-rising-water.cpp、java/0778-swim-in-rising-water.java、rust/0778-swim-in-rising-water.rs 等 12 种语言实现进行验证与练习。【免费下载链接】leetcodeLeetcode solutions项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

经营分析会如何驱动真实决策:目标-过程-结果三层PPT框架

经营分析会如何驱动真实决策:目标-过程-结果三层PPT框架

简介:本资源是一份面向企业经营分析岗位从业者及管理者的系统性培训课件,聚焦如何高效组织与开展运营分析会议,解决分析结果难落地、跨部门协同低效、报告价值感不足等实际痛点。课件以PPTX格式呈现,共1个文件,大小1.4…

2026/9/19 8:08:37 阅读更多 →
瑞数6.5逆向实战:RPC方案破解cookie sign与环境补全

瑞数6.5逆向实战:RPC方案破解cookie sign与环境补全

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 8:08:37 阅读更多 →
Vibe Coding:AI基础设施开发的文档驱动实践

Vibe Coding:AI基础设施开发的文档驱动实践

1. 项目背景与核心痛点在AI基础设施开发领域,工程师们长期面临着一个典型困境:系统复杂度呈指数级增长的同时,文档质量却往往线性下降。我经历过三个大型AI平台从零到一的构建过程,最深的体会是——当模型训练吞吐量从100 samples…

2026/9/19 8:08:37 阅读更多 →

最新新闻

Flutter for OpenHarmony实战:微动漫App分享功能从0到1实现

Flutter for OpenHarmony实战:微动漫App分享功能从0到1实现

把App从Android/iOS平移到OpenHarmony,本来以为就是改改依赖、换个编译目标的事,结果在分享功能上硬是折腾了近一周。这个项目是个微动漫App——用户可以刷到几秒到几十秒的循环动画、萌系表情包小短片,觉得好玩就一键保存并分享给朋友。分享…

2026/9/19 9:50:23 阅读更多 →
自研桌面端CRM系统DeskcommCRM:通信驱动客户管理与销售跟进实践

自研桌面端CRM系统DeskcommCRM:通信驱动客户管理与销售跟进实践

做这个项目之前,我一直对Web版CRM又爱又恨。爱的是部署省事、打开浏览器就能用,恨的是数据一多页面就卡、网络一抖连客户电话都调不出来,更别提销售团队每天在微信、邮件、企业IM和CRM之间来回切换,客户聊到哪儿了全靠人工记忆。后…

2026/9/19 9:50:23 阅读更多 →
Flutter ProgressIndicator 在 OpenHarmony 上的丝滑优化指南

Flutter ProgressIndicator 在 OpenHarmony 上的丝滑优化指南

1. 从定位到“丝滑”:为什么 ProgressIndicator 值得单独写一篇1.1 一个转圈组件背后的两种运行模式这一篇轮到 ProgressIndicator,说实话在编这个系列目录的时候,我就知道它早晚得来。前面三十二篇拆了容器、按钮、文本、图片这些“明面组件…

2026/9/19 9:50:23 阅读更多 →
React Native安全区适配鸿蒙实战指南

React Native安全区适配鸿蒙实战指南

1. 项目背景与核心挑战在鸿蒙生态中集成React Native框架时,安全区域适配是一个无法绕开的刚需功能。react-native-safe-area-context作为React Native社区最流行的安全区管理库,其鸿蒙化改造涉及到底层渲染机制、平台API调用和组件行为适配三个维度的技…

2026/9/19 9:50:23 阅读更多 →
Zeroclaw 会话历史管理机制解析:Token 预算裁剪与结构化消息数限制实战指南

Zeroclaw 会话历史管理机制解析:Token 预算裁剪与结构化消息数限制实战指南

Zeroclaw 会话历史管理机制解析:Token 预算裁剪与结构化消息数限制实战指南 【免费下载链接】zeroclaw Fast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platform — deploy anywhere, swap anything 🦀 项目地…

2026/9/19 9:50:23 阅读更多 →
NeDB排序、分页与投影:用Cursor API实现复杂数据检索的完整指南

NeDB排序、分页与投影:用Cursor API实现复杂数据检索的完整指南

NeDB排序、分页与投影:用Cursor API实现复杂数据检索的完整指南 【免费下载链接】nedb The JavaScript Database, for Node.js, nw.js, electron and the browser 项目地址: https://gitcode.com/gh_mirrors/ne/nedb NeDB 是一个 100% JavaScript 编写的内嵌…

2026/9/19 9:49:23 阅读更多 →

日新闻

BP神经网络时序预测:滑窗长度与多窗口平均策略

BP神经网络时序预测:滑窗长度与多窗口平均策略

简介:面向机器学习、深度学习与数据建模学习者的一份完整研究文献,聚焦BP神经网络在农业产量预测中的应用。文档以1980—2018年全国棉花产量为样本,系统讲解数据归一化处理、激活函数原理、多层神经网络结构搭建及训练流程,展示敏…

2026/9/19 0:00:30 阅读更多 →
Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

上个月调一个Deformable DETR模型,在单卡上要跑将近两天。第二天早上我下意识打开终端翻日志,发现loss从凌晨两点就开始往上爬,一路从0.8涨到1.35,整整六个小时没人发现。那六个小时的训练不仅白跑,还霸占着卡——等于…

2026/9/19 0:00:30 阅读更多 →
OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南 【免费下载链接】opencloud 🌤️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign. 项目地址: htt…

2026/9/19 0:00:30 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/19 3:59:36 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/19 3:53:08 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/19 4:02:43 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →