实现并查集类,解决连通性问题。(比如:朋友圈) 思路:把问题抽象成带有索引的数组。根据索引进行连通,从而得到连通个数。
class UnionFind{
private:
vector<int> parent;
vector<int> rank;
int count; // 省份个数
public:
UnionFind(unsigned int size)
{
for (int i = 0; i < size; i++) {
parent.push_back(i); // 自己的祖先是自己
rank.push_back(1); // 圈子大小初始状态都为1
}
count = size;
}
int Find(int p)
{
while (p != parent[p]) {
// TODO:路径压缩
parent[p] = parent[parent[p]]; // 路径压缩, 可减少一倍,也可不压缩
p = parent[p];
}
return p;
// return p == parent[p] ? p : parent[p] = Find(parent[p]);
}
void UnionElement(int p, int q)
{
int pRoot = Find(p);
int qRoot = Find(q);
if (qRoot == pRoot) {
return;
}
// 小圈子融入大圈子
if (rank[pRoot] < rank[qRoot]) {
parent[pRoot] = qRoot; // 不用维护层数
} else if (rank[pRoot] > rank[qRoot]) {
parent[qRoot] = pRoot; // 不用维护层数
} else {
parent[qRoot] = pRoot;
rank[pRoot]++; // 层数加1
}
count--;
}
int size() {
return count; // 返回圈子的个数
}
};
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected)
{
UnionFind *unionFind = new UnionFind(isConnected.size());
for (int i = 0; i < isConnected.size(); i++) {
for(int j = 0; j < isConnected[0].size(); j++) {
if (isConnected[i][j] == 1) {
unionFind->UnionElement(i, j);
}
}
}
return unionFind->size();
}
};
1. 题目
1631. 最小体力消耗路径
你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。
一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。
请你返回从左上角走到右下角的最小 体力消耗值 。
解决思路:1、二分+BFS。2、并查集、3、二分+DFS
// 并查集模板
class UnionFind{
private:
vector<int> parent;
vector<int> rank;
int count; // 省份个数
public:
UnionFind(unsigned int size)
{
for (int i = 0; i < size; i++) {
parent.push_back(i); // 自己的祖先是自己
rank.push_back(1); // 圈子大小初始状态都为1
}
count = size;
}
int Find(int p)
{
while (p != parent[p]) {
// TODO:路径压缩
parent[p] = parent[parent[p]]; // 路径压缩, 可减少一倍,也可不压缩
p = parent[p];
}
return p;
// return p == parent[p] ? p : parent[p] = Find(parent[p]);
}
void UnionElement(int p, int q)
{
int pRoot = Find(p);
int qRoot = Find(q);
if (qRoot == pRoot) {
return;
}
// 小圈子融入大圈子
if (rank[pRoot] < rank[qRoot]) {
parent[pRoot] = qRoot; // 不用维护层数
} else if (rank[pRoot] > rank[qRoot]) {
parent[qRoot] = pRoot; // 不用维护层数
} else {
parent[qRoot] = pRoot;
rank[pRoot]++; // 层数加1
}
count--;
}
int Size() {
return count; // 返回圈子的个数
}
bool Connected(int p, int q)
{
return Find(p) == Find(q);
}
};
class Solution {
public:
static bool cmp(tuple<int, int, int>& a, tuple<int, int, int>& b)
{
return get<2>(a) < get<2>(b);
}
int minimumEffortPath(vector<vector<int>>& heights)
{
int m = heights.size();
int n = heights[0].size();
vector<tuple<int, int, int>> edges;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int id = i * n + j; // 标记点的方式
if (i > 0) {
int id1 = (i - 1) * n + j; // 往上的点
edges.emplace_back(id1, id, abs(heights[i][j] - heights[i - 1][j]));
}
if (j > 0) {
int id1 = i * n + j - 1; // 往左的点
edges.emplace_back(id1, id, abs(heights[i][j] - heights[i][j - 1]));
}
}
}
sort(edges.begin(), edges.end(), cmp);
UnionFind uf(m * n);
int ans = 0;
for (const auto [x, y, v]: edges) {
uf.UnionElement(x, y);
if (uf.Connected(0, m * n - 1)) {
ans = v;
break;
}
}
return ans;
}
};