作者: 负雪明烛
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. nginx——网站显示问题

    一般来说修改3个位置,一个是nginx.h.另一个是ngx_http_header_filter_module.c.还有一个ngx_http_special_response.c. 提示:一般修改都是 ...

  2. 这份github上被14万人点赞的Java教程太强了

    前几天有个小伙伴加我之后问了下面的这个问题.我看到后是一脸懵逼的状态,jcombobox?实话说,我已经完全忘了在Java中还有这么个东西. 在网上一番搜索后,才发现原来它是 swing 中的下拉列表 ...

  3. 线性表A,B顺序存储合并

    线性表A,B顺序存储合并 有两张非递增有序的线性表A,B,采用顺序存储结构,两张表合并用c表存,要求C为非递减有序的,然后删除C表中值相同的多余元素.元素类型为整型 输入格式: 第一行输入输入表A的各 ...

  4. Identity Server 4 从入门到落地(七)—— 控制台客户端

    前面的部分: Identity Server 4 从入门到落地(一)-- 从IdentityServer4.Admin开始 Identity Server 4 从入门到落地(二)-- 理解授权码模式 ...

  5. aboard, abolish

    aboard board做动词有上车/船/飞机的意思,boarding就是正在上.board做名词有板的意思,车厢地板的板. a是个词根,有三种意思:1. 以某种状态或方式,如: ablaze, af ...

  6. Java 监控基础 - 使用 JMX 监控和管理 Java 程序

    点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码网站 已经收录,有很多知识点和系列文章. 此篇文 ...

  7. 我在项目中是这样配置Vue的

    启用压缩,让页面加载更快 在我们开发的时候,为了方便调试,我们需要使用源码进行调试,但在生产环境,我们追求的更多的是加载更快,体验更好,这时候我们会将代码中的空格注释去掉,对代码进行混淆压缩,只为了让 ...

  8. Thymeleaf标准表达式

    Thymeleaf的官网为: http://www.thymeleaf.org/ 一.变量表达式${-} 使用${-}括起来的表达式,称为变量表达式.该表达式的内容会显示在HTML标签体文本处. 该表 ...

  9. 使用jquery刷新页面以及javascript的一些基本函数

    如何使用jquery刷新当前页面 下面介绍全页面刷新方法:有时候可能会用到 1.window.location.reload()刷新当前页面. 2.parent.location.reload()刷新 ...

  10. 【Matlab】CFAR/phased.CFARDetector2D

    | CFAR学习进行时ing... | CFAR原理.参数 检测阈值\(T = αP_n\) \(P_n\)是噪声功率估计,\(α\)是比例因子 训练单元:训练噪声,估计\(P_n = \frac{1 ...