[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 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 time0
, 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 time3
.
When the depth of water is3
, 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:
2 <= N <= 50
.- grid[i][j] is a permutation of [0, ..., N*N - 1].
这道题给了我们一个二维数组,可以看作一个水池,这里不同数字的高度可以看作台阶的高度,只有当水面升高到台阶的高度时,我们才能到达该台阶,起始点在左上角位置,问我们水面最低升到啥高度就可以到达右下角的位置。这是一道蛮有意思的题目。对于这种类似迷宫遍历的题,一般都是DFS或者BFS。而如果有极值问题存在的时候,一般都是优先考虑BFS的,但是这道题比较特别,有一个上升水面的设定,我们可以想象一下,比如洪水爆发了,大坝垮了,那么愤怒汹涌的水流冲了出来,地势低洼处就会被淹没,而地势高的地方,比如山峰啥的,就会绕道而过。这里也是一样,随着水面不断的上升,低于水平面的地方就可以到达,直到水流到了右下角的位置停止。因为水流要向周围低洼处蔓延,所以BFS仍是一个不错的选择,由于水是向低洼处蔓延的,而低洼处的位置又是不定的,所以我们希望每次取出最低位置进行遍历,那么使用最小堆就是一个很好的选择,这样高度低的就会被先处理。在每次取出高度最小的数字时,我们用此高度来更新结果res,如果当前位置已经是右下角了,则我们直接返回结果res,否则就遍历当前位置的周围位置,如果未越界且未被访问过,则标记已经访问过,并且加入队列,参见代码如下:
解法一:
class Solution {
public:
int swimInWater(vector<vector<int>>& grid) {
int res = , n = grid.size();
unordered_set<int> visited{};
vector<vector<int>> dirs{{, -}, {-, }, {, }, {, }};
auto cmp = [](pair<int, int>& a, pair<int, int>& b) {return a.first > b.first;};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp) > q(cmp);
q.push({grid[][], });
while (!q.empty()) {
int i = q.top().second / n, j = q.top().second % n; q.pop();
res = max(res, grid[i][j]);
if (i == n - && j == n - ) return res;
for (auto dir : dirs) {
int x = i + dir[], y = j + dir[];
if (x < || x >= n || y < || y >= n || visited.count(x * n + y)) continue;
visited.insert(x * n + y);
q.push({grid[x][y], x * n + y});
}
}
return res;
}
};
我们也可以使用DP+DFS来做,这里使用一个二维dp数组,其中 dp[i][j] 表示到达 (i, j) 位置所需要的最低水面高度,均初始化为整型数最大值,我们的递归函数函数需要知道当前的位置 (x, y),还有当前的水高cur,同时传入grid数组和需要不停更新的dp数组,如果当前位置越界了,或者是当前水高和 grid[x][y] 中的较大值大于等于 dp[x][y] 了,直接跳过,因为此时的dp值更小,不需要被更新了。否则 dp[x][y] 更新为较大值,然后对周围四个位置调用递归函数继续更新dp数组,最终返回右下位置的dp值即可,参见代码如下:
解法二:
class Solution {
public:
vector<vector<int>> dirs{{, -}, {-, }, {, }, {, }};
int swimInWater(vector<vector<int>>& grid) {
int n = grid.size();
vector<vector<int>> dp(n, vector<int>(n, INT_MAX));
helper(grid, , , grid[][], dp);
return dp[n - ][n - ];
}
void helper(vector<vector<int>>& grid, int x, int y, int cur, vector<vector<int>>& dp) {
int n = grid.size();
if (x < || x >= n || y < || y >= n || max(cur, grid[x][y]) >= dp[x][y]) return;
dp[x][y] = max(cur, grid[x][y]);
for (auto dir : dirs) {
helper(grid, x + dir[], y + dir[], dp[x][y], dp);
}
}
};
其实这道题还可以使用二分搜索法来做,属于博主的总结帖中LeetCode Binary Search Summary 二分搜索法小结的第四类,用子函数当作判断关系。由于题目中给定了数字的范围,那么二分搜索法的左右边界就有了,然后我们计算一个中间值mid,调用子函数来看这个水面高度下能否到达右下角,如果不能的话,说明水面高度不够,则 left = mid+1,如果能到达的话,有可能水面高度过高了,则right = mid,最终会到达的临界点就是能到达右下角的最低水面高度。那么来看子函数怎么写,其实就是个迷宫遍历问题,我们可以使用BFS或者DFS,这里使用了stack辅助的迭代形式的DFS来遍历,当然我们也可以使用queue辅助的迭代形式的BFS来遍历,都一样,如果在mid的水面高度下,遍历到了右下角,则返回true,否则返回false,参见代码如下:
解法三:
class Solution {
public:
int swimInWater(vector<vector<int>>& grid) {
int n = grid.size();
int left = grid[][], right = n * n;
while (left < right) {
int mid = left + (right - left) / ;
if (!helper(grid, mid)) left = mid + ;
else right = mid;
}
return left;
}
bool helper(vector<vector<int>>& grid, int mid) {
int n = grid.size();
unordered_set<int> visited{};
vector<vector<int>> dirs{{, -}, {-, }, {, }, {, }};
stack<int> st{{}};
while (!st.empty()) {
int i = st.top() / n, j = st.top() % n; st.pop();
if (i == n - && j == n - ) return true;
for (auto dir : dirs) {
int x = i + dir[], y = j + dir[];
if (x < || x >= n || y < || y >= n || visited.count(x * n + y) || grid[x][y] > mid) continue;
st.push(x * n + y);
visited.insert(x * n + y);
}
}
return false;
}
};
参考资料:
https://leetcode.com/problems/swim-in-rising-water/solution/#
https://leetcode.com/problems/swim-in-rising-water/discuss/113743/JAVA-DP-+-DFS
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Swim in Rising Water 在上升的水中游泳的更多相关文章
- 【LeetCode】778. Swim in Rising Water 水位上升的泳池中游泳(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/swim-in- ...
- 【leetcode】778. Swim in Rising Water
题目如下: 解题思路:本题题干中提到了一个非常重要的前提:"You can swim infinite distance in zero time",同时也给了一个干扰条件,那就是 ...
- LeetCode 778. Swim in Rising Water
题目链接:https://leetcode.com/problems/swim-in-rising-water/ 题意:已知一个n*n的网格,初始时的位置为(0,0),目标位置为(n-1,n-1),且 ...
- [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 ...
- 778. Swim in Rising Water
▶ 给定方阵 grid,其元素的值为 D0n-1,代表网格中该点处的高度.现在网格中开始积水,时刻 t 的时候所有值不大于 t 的格点被水淹没,当两个相邻格点(上下左右四个方向)的值都不超过 t 的时 ...
- leetcode#42 Trapping rain water的五种解法详解
leetcode#42 Trapping rain water 这道题十分有意思,可以用很多方法做出来,每种方法的思想都值得让人细细体会. 42. Trapping Rain WaterGiven n ...
- [array] leetcode - 42. Trapping Rain Water - Hard
leetcode - 42. Trapping Rain Water - Hard descrition Given n non-negative integers representing an e ...
- LeetCode 42. Trapping Rain Water 【两种解法】(python排序遍历,C++ STL map存索引,时间复杂度O(nlogn))
LeetCode 42. Trapping Rain Water Python解法 解题思路: 本思路需找到最高点左右遍历,时间复杂度O(nlogn),以下为向左遍历的过程. 将每一个点的高度和索引存 ...
- [LeetCode] 407. Trapping Rain Water II 收集雨水 II
Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...
随机推荐
- css中的数学表达式calc()
前言 数学表达式calc()是CSS中的函数,主要用于数学运算.使用calc()为页面元素布局提供了便利和新的思路. 概念 数学表达式calc()是calculate计算的缩写,它允许使用+.-.*. ...
- 函数语法:currentStyle、getComputedStyle兼容判断
var oDiv = document.getElementById('aa'); if(oDiv.currentStyle){ var style = oDiv.currentStyle; aler ...
- xls表格 ctrl+D 和ctrl+Enter区别 --快速填充相同数据,同时填充多个不同数据
一.ctrl+Enter应用 如何快速实现下图两个图的填充值效果? ==>效果 1. 选择A列,或者所需要填充的范围 (下面利用 ctrl+G定位应用) 2.Ctrl+G 定位 选择 空值 在 ...
- idea一款颜值很高的theme
在idea的plugins搜索theme,能看到一款人气值超高的插件,下载使用了确实很漂亮!
- HTTP报错401和403详解及解决办法
一.401: 1. HTTP 401 错误 - 未授权: (Unauthorized) 您的Web服务器认为,客户端发送的 HTTP 数据流是正确的,但进入网址 (URL) 资源 , 需要用户身份验证 ...
- 分布式系列六: WebService简介
WebSerice盛行的时代已经过去, 这里只是简单介绍下其基本概念, 并用JDK自带的API实现一个简单的服务. WebSerice的概念 WebService是一种跨平台和跨语言的远程调用(RPC ...
- java PDF2JPG
import org.apache.commons.lang3.StringUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org ...
- windows配置Erlang环境
1.说明 1.1 操作系统 win10x64 1.2 Erlang(['ə:læŋ])是一种通用的面向并发的编程语言,它由瑞典电信设备制造商爱立信所辖的CS-Lab开发,目的是创造一种可以应对大规模并 ...
- 题解 P5065 【[Ynoi2014]不归之人与望眼欲穿的人们】
出现了一篇跑得炒鸡慢的题解! noteskey 无 fuck 说,好像就是整个数列分块然后合并区间...什么的吧 对于每块内部就是算一下前缀信息.后缀信息(就是以 第一个点/最后一个点 为一个边界,不 ...
- 分享腾讯云的Linux服务器连接速度很慢的解决心得(原创)
最近发觉连接服务器非常慢,之前没有出现过这种情况. 我在这个腾讯云的服务器上弄了很多虚拟服务器,估计是数据量太大 造成了冗余数据较多的原因,咨询了下腾讯云的小哥, 给我了个明确的回复: 您反馈Xshe ...