等式方程的可满足性——并查集
题目
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:a==b 或 a!=b。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
代码
private class UnionFind {
private int[] parent;
public UnionFind(int n) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
// 在这里用的是隔代路径压缩,较彻底路径压缩(递归实现)而言,虽压缩不完全但性能较高
public int find(int x) {
while (x != parent[x]) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
parent[rootX] = rootY;
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
}
public boolean equationsPossible(String[] equations) {
UnionFind unionFind = new UnionFind(26);
for (String equation : equations) {
char[] charArr = equation.toCharArray();
if (charArr[1] == '=') {
int index1 = charArr[0] - 'a';
int index2 = charArr[3] - 'a';
unionFind.union(index1, index2);
}
}
for (String equation : equations) {
char[] charArr = equation.toCharArray();
if (charArr[1] == '!') {
int index1 = charArr[0] - 'a';
int index2 = charArr[3] - 'a';
if (unionFind.isConnected(index1, index2)) {
return false;
}
}
}
return true;
} 题外话
今天做到这个题学到了一个新知识点——并查集,就做个记录总结下。
CSDN博主的一篇文章将并查集讲述的生动形象,可以前往阅览。
相关概念
- 并查集 是一种树型的数据结构,用来处理一些不交集的 合并 及 查询 问题。
- 并查集森林 是一种将每一个集合以树表示的数据结构,其中每一个节点保存着到它父节点的引用。
代码实现
其中主要就是 find 和 union 两个方法。
find 方法用来寻找两个节点的根节点,如果两个节点的根节点一致,两个节点就是连通的。在寻找时可以进行路径压缩来优化查找效率。举个例子,假设原来的树内节点构成了一条线,则查找效率为 O(n),而如果在每次查找后将当前节点连接到父节点的父结点上(隔代路径压缩),或者直接将查找节点连接到根节点(彻底路径压缩)。那么经过多次的查找,当前树的深度就会变得很低,可以方便的找到当前节点所在树的根节点。
隔代路径压缩
public int find(int x) { while (x != parent[x]) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; }彻底路径压缩
public int find(int x) { if (parent[x]!=x) { parent[x] = find(parent[x]); } return parent[x]; }
union 方法是用来连结两个原来不相关的树,实现也较为简单,找到两个节点所在树的根节点,将其中一个根节点指向另外一个根节点即可。
并查集的具体代码如下:
private class UnionFind {
private int[] parent;
public UnionFind(int n) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
// 在这里用的是隔代路径压缩,较彻底路径压缩(递归实现)而言,虽压缩不完全但性能较高
public int find(int x) {
while (x != parent[x]) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
parent[rootX] = rootY;
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
}
三奇智元机器人科技有限公司公司福利 50人发布
查看6道真题和解析