问题描述
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i]
的长度为 4
,并采用两种不同的形式之一:"a==b"
或 "a!=b"
。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true
,否则返回 false
。
示例 1:
输入:[“a==b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
解题报告
并查集主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作
- 合并(Union):把两个不相交的集合合并为一个集合
- 查询(Find):查询两个元素是否在同一集合中。
算法步骤:
- 将所有具有相等关系的字母进行
merge
。 - 然后遍历所有不相等的关系,如果发现不相等的两个字母在同一个集合中,那么直接返回
false
同时使用了 路径压缩 和 按秩合并 的优化策略。
实现代码
class Solution{
public:
unordered_map<int, int>parent, cnt;
int find(int index){
return parent[index]==index?index:parent[index]=find(parent[index]);
}
void merge(int a, int b){
a=find(a);
b=find(b);
if(a==b) return;
// 按秩合并,为了使得合并后的子树高度尽量低,
// 需要把高度晓得那棵子树接在高度高的那个树下
if(cnt[a]<cnt[b]){
parent[a]=b;
cnt[b]+=cnt[a];
}
else{
parent[b]=a;
cnt[a]+=cnt[b];
}
}
bool equationsPossible(vector<string>&equations){
for(int i=0;i<26;i++){
parent[i]=i;
cnt[i]=1;
}
for (const string& str: equations) {
if (str[1] == '=') {
int index1 = str[0] - 'a';
int index2 = str[3] - 'a';
merge(index1, index2);
}
}
for (const string& str: equations) {
if (str[1] == '!') {
int index1 = str[0] - 'a';
int index2 = str[3] - 'a';
if (find(index1) == find(index2)) {
return false;
}
}
}
return true;
}
};
参考资料
[1] Leetcode 990. 等式方程的可满足性
[2] 算法学习笔记(1) : 并查集
[3]