Leetcode 778. Swim in Rising Water

Problem:

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].

Solution:

  这两天刷了几道非常规的Binary Search题,总算是有了点感觉。看到这道题也是第一时间内想到了解法,还是挺爽的。这道题由于游泳速度是无限大的,所以我们只需要找到一个最小值,使得在这个矩阵内存在路径从左上角走到右下角,题目中还有个隐藏条件,就是矩阵的元素范围是0-N*N,所以直觉告诉我可以用Binary Search,而且也是那种非常规的Binary Search。通过二分法找到left和right的中间值pivot,然后去验证在pivot时间时是否存在从左上角到右下角的路径,当然也可以用BFS或DFS来验证,但我比较喜欢Union Find这种比较优雅的方式。这里的Union Find我取消了rank函数,并把二位数组压缩为一维,因为这里Union的原则是往索引值小的那一方Union,最后确认N*N-1的根节点是否为0即可。

Code:

 

 1 class Solution {
 2 public:
 3     int Find(vector<int> &parent,int target){
 4         if(parent[target] == target)
 5             return target;
 6         return Find(parent,parent[target]);
 7     }
 8     void Union(vector<int> &parent,int x,int y){
 9         int px = Find(parent,x);
10         int py = Find(parent,y);
11         if(px == py) return;
12         if(px > py) parent[px] = py;
13         else parent[py] = px;
14     }
15     int swimInWater(vector<vector<int>>& grid) {
16         int m = grid.size();
17         int left = 0;
18         int right = m*m-1;
19         while(left < right){
20             int pivot = left+(right-left)/2;
21             vector<int> parent(m*m);
22             for(int i = 0;i != m*m;++i)
23                 parent[i] = i;
24             for(int i = 0;i != m;++i){
25                 for(int j = 0;j != m;++j){
26                     if(grid[i][j] > pivot) continue;
27                     if(i-1 >= 0 && grid[i-1][j] <= pivot) Union(parent,i*m+j,(i-1)*m+j);
28                     if(i+1 < m && grid[i+1][j] <= pivot) Union(parent,i*m+j,(i+1)*m+j);
29                     if(j-1 >= 0 && grid[i][j-1] <= pivot) Union(parent,i*m+j,i*m+j-1);
30                     if(j+1 < m && grid[i][j+1] <= pivot) Union(parent,i*m+j,i*m+j+1);
31                 }
32             }
33             if(Find(parent,m*m-1) == 0)
34                 right = pivot;
35             else
36                 left = pivot+1;
37         }
38         return left;
39     }
40 };

 

转载于:https://www.cnblogs.com/haoweizh/p/10201316.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值