题目
在一个 N x N 的坐标方格grid
中,每一个方格的值grid[i][j]
表示在位置 (i,j) 的平台高度。
现在开始下雨了。当时间为t
时,此时雨水导致水池中任意位置的水位为t
。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。当然,在你游泳的时候你必须待在坐标方格里面。
你从坐标方格的左上平台 (0,0) 出发。最少耗时多久你才能到达坐标方格的右下平台 (N-1, N-1)?
示例
输入: [[0,2],[1,3]]
输出: 3
解释:
时间为0时,你位于坐标方格的位置为 (0, 0)。
此时你不能游向任意方向,因为四个相邻方向平台的高度都大于当前时间为 0 时的水位。
等时间到达 3 时,你才可以游向平台 (1, 1). 因为此时的水位是 3,坐标方格中的平台没有比水位 3 更高的,所以你可以游向坐标方格中的任意位置
思路
由题意可知,t
时间的水位高度为t
,则某一个格的高度就是水恰好淹没该格的时间,也即“我们”能游到该格的最早时间。
从起点游到到终点的时间(因为游泳不消耗时间,其实只有从低格子到高格子的等待时间),就是通过路径中格子的最大高度。
由于游泳的方向不定,如果考虑格子则需要分类讨论。不如考虑边:
- 行列各有
n*(n-1)
条边,需要两次双重循环遍历图得到所有的边。
- 考虑可以通过该边的最早时间(能从一端游到另一端的最早时间),即为两端点高度的最大值。
- 以三元组
(i, j, arrival)
的形式表示一条边。
算法过程类似Kruskal
算法的思想:
- 首先对边按最早到达时间进行排序,然后依次选取最小的边。
- 在并查集中连接两点,若还未连通,则选取该边则并更新时间t为该边的最早到达时间。
- 当第一次起点和终点连通时,即退出,返回当前时间
t
。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| class UnionFindSet { private: vector<int> parent, rank;
public: int size; int extra; int cp; UnionFindSet(int n); ~UnionFindSet(); int find(int x); bool Union(int x, int y); void print(); int getCP(); };
UnionFindSet::UnionFindSet(int n) { extra = 0; cp = 0; size = n; rank.resize(n, 1); parent.resize(n); for (int i = 0; i < n; i++) { parent[i] = i; } }
UnionFindSet::~UnionFindSet() { }
int UnionFindSet::find(int x) { return parent[x] = parent[x] != x ? find(parent[x]) : parent[x]; }
bool UnionFindSet::Union(int x, int y) { int fx = find(x); int fy = find(y); if (fx == fy) { extra ++; return false; } if (rank[fx] < rank[fy]) { swap(fx, fy); } parent[fy] = fx; rank[fx] += rank[fy]; return true; }
void UnionFindSet::print() { for (int i = 0; i < size; i++) {
std::cout<<i<<" -> "<<parent[i]<<endl; } }
int UnionFindSet::getCP() { for (int i = 0; i < size; i++) { if(parent[i] == i){ cp++; } } return cp; }
class edge { public: int i, j, arrival; edge(int _i, int _j, int _arrival){ i = _i; j = _j; arrival = _arrival; } };
class Solution { public: int swimInWater(vector<vector<int>>& grid) { int n = grid.size(); int t = 0; UnionFindSet ufs(n*n); vector<edge> edges; for(int i=0;i<n;i++){ for(int j=0;j<n-1;j++){ int index = n*i+j; edges.emplace_back(index, index+1, max(grid[i][j], grid[i][j+1])); } } for(int j=0;j<n;j++){ for(int i=0;i<n-1;i++){ int index = n*i+j; edges.emplace_back(index, index+n, max(grid[i][j], grid[i+1][j])); } } sort(edges.begin(), edges.end(), [](edge a, edge b) -> bool { return a.arrival < b.arrival; }); for(auto& [ni, nj, arrival]: edges){ if(ufs.Union(ni, nj)) { t = max(arrival, t); if(ufs.find(n*n - 1) == ufs.find(0)){ return t; } } } return 0; } };
|