作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址: https://leetcode.com/problems/swim-in-rising-water/description/

题目描述:

On an N x N grid, each square grid[i][j] represents the elevation at that point (i,j).

Now rain starts to fall. At time t, the depth of the water everywhere is t. You can swim from a square to another 4-directionally adjacent square if and only if the elevation of both squares individually are at most t. You can swim infinite distance in zero time. Of course, you must stay within the boundaries of the grid during your swim.

You start at the top left square (0, 0). What is the least time until you can reach the bottom right square (N-1, N-1)?

Example 1:

Input: [[0,2],[1,3]]
Output: 3
Explanation:
At time 0, you are in grid location (0, 0).
You cannot go anywhere else because 4-directionally adjacent neighbors have a higher elevation than t = 0. You cannot reach point (1, 1) until time 3.
When the depth of water is 3, we can swim anywhere inside the grid.

Example 2:

Input: [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
Output: 16
Explanation:
0 1 2 3 4
24 23 22 21 5
12 13 14 15 16
11 17 18 19 20
10 9 8 7 6 The final route is marked in bold.
We need to wait until time 16 so that (0, 0) and (4, 4) are connected.

Note:

  1. 2 <= N <= 50.
  2. grid[i][j] is a permutation of [0, …, N*N - 1].

题目大意

在一个 N x N 的坐标方格 grid 中,每一个方格的值 grid[i][j] 表示在位置 (i,j) 的平台高度。

现在开始下雨了。当时间为 t 时,此时雨水导致水池中任意位置的水位为 t 。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。当然,在你游泳的时候你必须待在坐标方格里面。

你从坐标方格的左上平台 (0,0) 出发。最少耗时多久你才能到达坐标方格的右下平台 (N-1, N-1)?

解题方法

并查集

从左上角通往右下角的路径中,消耗的时间肯定是道路上最高的那个格子的高度。对于这种问题,也是像昨天题目一样,当做连通性问题来解决。

判断是否连通常见的办法是:并查集

昨天的每日一题为「1631. 最小体力消耗路径」,它是求从左上角到右下角的所有路径中的最小高度差绝对值,跟本题非常像。建议大家先阅读昨天的题解:1631. 最小体力消耗路径。

今天题目和昨天题目的不同之处:

  • 昨天的题目是把相邻的两个格子之间的高度差的绝对值当作了边的权重,对边排序,逐渐添加边,看添加到哪个边的时候,起点和终点能连通;
  • 今天的题目中,由于不用求高度差,而是求路径上的格子高度的最大值,因此,可以把抽象成为一个边的权重为 0 的无向图,然后对顶点排序,逐个添加上每个顶点,看添加到哪个点的时候,起点和终点能连通。

需要注意题目中的一个条件:grid[i][j][0, ..., N*N - 1] 的排列。因此图中没有大小相等的顶点。

整体思路是:

  1. 先去除图中的所有顶点,然后按照顶点数值的从小到大的顺序,依次遍历并添加每个顶点;
  2. 在每次遍历的过程中都要比较这个顶点的数值和其周围的 4 个相邻顶点的数值大小,来判断是否需要添加一条边:如果相邻节点的数值更小,说明该相邻顶点之前已经添加到图中,因此现在需要建立一条让两个顶点连通的边;如果相邻节点的数值更大,说明该相邻顶点之前没有添加到图中,因此不要建立连通的边。
  3. 当添加某一个顶点之后,最左上角的顶点和最右下角的顶点连通了,说明该顶点就是所求。

整个流程就如下面的动画所示(该动画来自力扣官方题解,地址:https://leetcode-cn.com/problems/swim-in-rising-water/solution/shui-wei-shang-sheng-de-yong-chi-zhong-y-862o/):

![](https://img-blog.csdnimg.cn/img_convert/3db801dd20cb99441f5c6e3592c8b4d5.gif#align=left&display=inline&height=608&margin=[object Object]&name=&originHeight=608&originWidth=1080&size=0&status=done&style=none&width=1080)

二分查找 + DFS

题意是要求我们,找出一个最小的时间t,在t时刻时所有位置的水面的高度都是t,这时能从左上角的位置到达右下角。

既然指定了开始和结束的位置,可以直接使用DFS或者BFS进行搜索。这个题需要做的就是我们在每个时间t的时候,判断我们能否找到一个有效的路径,如果使用dfs搜索的话,需要判断两个格子的水位相等才行,因为只有海拔相等的情况下,才能保证游过去。因为每个格子自身都有个海拔,所以判断当前高度的方法其实是时刻与自身海拔的最大值。

为了加快搜索,使用了二分查找,题目已经说了所有的数字0~N*N-1之间,每次做二分的时候都要完整的做一次DFS,还好题目规模不大。

时间复杂度是O(N^2*log(N)),空间复杂度是O(N^2)

class Solution(object):
def swimInWater(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
n = len(grid)
left, right = 0, n * n - 1
while left <= right:
mid = left + (right - left) / 2
if self.dfs([[False] * n for _ in range(n)], grid, mid, n, 0, 0):
right = mid - 1
else:
left = mid + 1
return left def dfs(self, visited, grid, mid, n, i, j):
visited[i][j] = True
if i == n - 1 and j == n - 1:
return True
directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]
for dir in directions:
x, y = i + dir[0], j + dir[1]
if x < 0 or x >= n or y < 0 or y >= n or visited[x][y] or max(mid, grid[i][j]) != max(mid, grid[x][y]):
continue
if self.dfs(visited, grid, mid, n, x, y):
return True
return False

优先级队列改进的 BFS

这个思路是,从左上角通往右下角的路径中,瓶颈是哪个呢?肯定是那个必经的道路上有个比较高的。所以,我们只要在做BFS时候,优先走比较矮的路,同时把最高的那个保存下来,就是结果。

class Solution(object):
def swimInWater(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
n = len(grid)
visited, pq = set((0, 0)), [(grid[0][0], 0, 0)]
res = 0
while pq:
T, i, j = heapq.heappop(pq)
res = max(res, T)
directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]
if i == j == n - 1:
break
for dir in directions:
x, y = i + dir[0], j + dir[1]
if x < 0 or x >= n or y < 0 or y >= n or (x, y) in visited:
continue
heapq.heappush(pq, (grid[x][y], x, y))
visited.add((x, y))
return res

参考资料:

https://leetcode.com/problems/swim-in-rising-water/discuss/113770/Easy-and-Concise-Solution-using-PriorityQueue-PythonC++
https://blog.csdn.net/u014688145/article/details/79254332

日期

2018 年 10 月 2 日 —— 小蓝单车莫名其妙收了我1块钱,明明每个月免费骑10次的啊!
2021 年 1 月 31 日 —— 2021已经过了1/12,今天公众号发题晚了,阅读量比较低。

【LeetCode】778. Swim in Rising Water 水位上升的泳池中游泳(Python)的更多相关文章

  1. LeetCode 778. Swim in Rising Water

    题目链接:https://leetcode.com/problems/swim-in-rising-water/ 题意:已知一个n*n的网格,初始时的位置为(0,0),目标位置为(n-1,n-1),且 ...

  2. Java实现 LeetCode 778 水位上升的泳池中游泳(二分+DFS)

    778. 水位上升的泳池中游泳 在一个 N x N 的坐标方格 grid 中,每一个方格的值 grid[i][j] 表示在位置 (i,j) 的平台高度. 现在开始下雨了.当时间为 t 时,此时雨水导致 ...

  3. 【leetcode】778. Swim in Rising Water

    题目如下: 解题思路:本题题干中提到了一个非常重要的前提:"You can swim infinite distance in zero time",同时也给了一个干扰条件,那就是 ...

  4. [Swift]LeetCode778. 水位上升的泳池中游泳 | Swim in Rising Water

    On an N x N grid, each square grid[i][j]represents the elevation at that point (i,j). Now rain start ...

  5. 778. Swim in Rising Water

    ▶ 给定方阵 grid,其元素的值为 D0n-1,代表网格中该点处的高度.现在网格中开始积水,时刻 t 的时候所有值不大于 t 的格点被水淹没,当两个相邻格点(上下左右四个方向)的值都不超过 t 的时 ...

  6. [LeetCode] Swim in Rising Water 在上升的水中游泳

    On an N x N grid, each square grid[i][j] represents the elevation at that point (i,j). Now rain star ...

  7. 【一天一道LeetCode】#42. Trapping Rain Water

    一天一道LeetCode系列 (一)题目 Given n non-negative integers representing an elevation map where the width of ...

  8. Leetcode之深度优先搜索(DFS)专题-329. 矩阵中的最长递增路径(Longest Increasing Path in a Matrix)

    Leetcode之深度优先搜索(DFS)专题-329. 矩阵中的最长递增路径(Longest Increasing Path in a Matrix) 深度优先搜索的解题详细介绍,点击 给定一个整数矩 ...

  9. [LeetCode] 186. Reverse Words in a String II 翻转字符串中的单词 II

    Given an input string, reverse the string word by word. A word is defined as a sequence of non-space ...

随机推荐

  1. 如何利用nrfjprog.exe读写nrf51的flash

    版权声明:本文为博主原创文章,未经博主允许不得转载.   1.目的 为了方便平时在开发中的调试,验证一些想法是否正确. 2.平台: Jlink version:v5.02c nrf51822硬件板等. ...

  2. 构建LNMP+WordPress

    1. 安装LNMP环境 首先修改主机名 [root@samba ~]# hostnamectl set-hostname lnmp[root@lnmp lnmp1.6-full]# hostnamec ...

  3. 【Redis集群原理专题】分析一下相关的Redis集群模式下的脑裂问题!

    技术格言 世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程. 什么是脑裂 字面含义 首先,脑裂从字面上理解就是脑袋裂开了,就是思想分家了,就是有了两个山头,就是有了 ...

  4. flink-----实时项目---day04-------1. 案例:统计点击、参与某个活动的人数和次数 2. 活动指标多维度统计(自定义redisSink)

    1. 案例 用户ID,活动ID,时间,事件类型,省份 u001,A1,2019-09-02 10:10:11,1,北京市 u001,A1,2019-09-02 14:10:11,1,北京市 u001, ...

  5. 转 proguard 混淆工具的用法 (适用于初学者参考)

    转自:https://www.cnblogs.com/lmq3321/p/10320671.html 一. ProGuard简介 附:proGuard官网 因为Java代码是非常容易反编码的,况且An ...

  6. IntentFilter,PendingIntent

    1.当Intent在组件间传递时,组件如果想告知Android系统自己能够响应那些Intent,那么就需要用到IntentFilter对象. IntentFilter对象负责过滤掉组件无法响应和处理的 ...

  7. 【Linux】【Services】【SaaS】Docker+kubernetes(13. 部署Jenkins/Maven实现代码自动化发布)

    1. 简介 Jenkins: 官方网站:https://jenkins.io/ 下载地址:https://jenkins.io/download/ war包下载:http://mirrors.jenk ...

  8. 【Spring Framework】Spring入门教程(八)Spring的事务管理

    事务是什么? 事务:指单个逻辑操作单元的集合. 在操作数据库时(增删改),如果同时操作多次数据,我们从业务希望,要么全部成功,要么全部失败.这种情况称为事务处理. 例如:A转账给B. 第一步,扣除A君 ...

  9. Webpack学习篇

    <深入浅出Webpack>优化篇 01 Webpack 优化可以分为开发优化和输出质量优化两部分,主要要点如下: 优化开发体验,提升开发效率 优化构建速度 优化使用体验 优化输出质量 减少 ...

  10. Apache Hudi 与 Hive 集成手册

    1. Hudi表对应的Hive外部表介绍 Hudi源表对应一份HDFS数据,可以通过Spark,Flink 组件或者Hudi客户端将Hudi表的数据映射为Hive外部表,基于该外部表, Hive可以方 ...