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