题目描述
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a==b” 或 “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
提示
1 <= equations.length <= 500
equations[i].length == 4
equations[i][0] 和 equations[i][3] 是小写字母
equations[i][1] 要么是 ‘=’,要么是 ‘!’
equations[i][2] 是 ‘=’
解题思路
小白第一次遇到并查集,百度了一下并查集的用法,又查看了大佬们的题解,做一下总结。这道题主要分为以下几步:
- 初始化等价类:每个元素都是独立的一个集合。
- 通过“==“确定等价类:根据等式创建不同的集合,并利用树来表示每个集合,树的根节点即为集合名。在遍历树的过程中,通过路径压缩的方式降低搜索花费。
(注:上图仍可继续压缩)
- 通过“!=“发现矛盾
代码
class Solution {
public:
int father[26];
bool equationsPossible(vector<string>& equations)
{
for(int i = 0; i < 26; i++)
father[i] = i;
//根据“==“压缩路径
for(int i = 0; i < equations.size(); i++)
{
if(equations[i][1] == '=')
{
int p1 = find(equations[i][0] - 'a');
int p2 = find(equations[i][3] - 'a');
if(p1 != p2)
father[p1] = p2;
}
}
//根据”!=”发现矛盾
for(int i = 0; i < equations.size(); i++)
{
if(equations[i][1] == '!')
{
int p1 = find(equations[i][0] - 'a');
int p2 = find(equations[i][3] - 'a');
if(p1 == p2)
return false;
}
}
return true;
}
//find非递归写法
int find(int obj)
{
//检查是否为根节点,根节点本身即为自己的根节点,所以有obj == father[obj]
while(obj != father[obj])
{
father[obj] = father[father[obj]]; //压缩路径,使自己父节点的父节点成为自己的父节点
obj = father[obj]; //准备查看当前节点的父节点
}
return obj;
}
/*
//find递归写法,可运行
int find(int obj)
{
if(obj != father[obj])
return father[obj] = find(father[obj]);
else
return obj;
}
*/
};