1970. 你能穿过矩阵的最后一天
题目链接:1970. 你能穿过矩阵的最后一天
代码如下:
cpp
//参考链接:https://leetcode.cn/problems/last-day-where-you-can-still-cross/solutions/936629/dao-xu-bing-cha-ji-by-endlesscheng-canj
class UnionFind {
public:
UnionFind(int n) :fa(n) {
// 一开始有n个集合 {0},{1}...{n-1}
//集合i的代表元是自己
ranges::iota(fa, 0);
}
//返回x所在集合的代表元
//同时做路径压缩,也就是把x所在集合中所有元素的fa都改成代表元
int find(int x) {
//如果fa[x]==x,则表示x是代表元
if (fa[x] != x) {
fa[x] = find(fa[x]);//fa改成代表元
}
return fa[x];
}
//判断x和y是否在同一个集合
bool is_same(int x, int y) {
//如果x的代表元和y的代表元相同,那么x和y就在同一个集合
//这就是代表元的作用:用来迅速判断两个元素是否在同一个集合
return find(x) == find(y);
}
//把from所在集合合并到to所在集合中
void merge(int from, int to) {
int x = find(from), y = find(to);
fa[x] = y;// 合并集合,修改后就可以认为from 和 to在同一个集合了
}
private:
vector<int> fa; // 代表元
};
class Solution {
public:
int latestDayToCross(int row, int col, vector<vector<int>>& cells) {
int top = row * col;
int bottom = row * col + 1;
UnionFind uf(row * col + 2);
vector<vector<int8_t>> land(row, vector<int8_t>(col));
for (int day = cells.size() - 1;;day--) {
auto& cell = cells[day];
int r = cell[0] - 1; // 改成从0开始的下标
int c = cell[1] - 1;
int v = r * col + c;
land[r][c] = true; //突变陆地
if (r == 0) {
uf.merge(v, top);// 与最上面相连
}
if (r == row - 1) {
uf.merge(v, bottom);// 与最下面相连
}
for (auto& d : DIRS) {
int x = r + d[0], y = c + d[1];
if (0 <= x && x < row && 0 <= y && y < col && land[x][y]) {
uf.merge(v, x * col + y);//与四周的陆地相连
}
}
//最上边和最下边相连
if (uf.is_same(top, bottom)) {
return day;
}
}
}
private:
//左右上下
static constexpr int DIRS[4][2] = { {0,-1},{0,1},{-1,0},{1,0} };
};