这里是题目描述:LeetCode-990.等式方程的可满足性
本题使用并查集来解,难度并不大,大体方法是:首先遍历题目给出的字符串数组equations
建立并查集,如果遍历到的字符串包含"=="
,则对"=="
两边的字符建立并查集,如果两个字符均没有包含在一个集合中,则新建立一个集合包含它们;如果两个字符只有一个包含在某个集合中或两个字符分别在不同的集合中,则将它们合并入一个集合中;如果两个字符位于同一个集合中,则不用进行任何操作 。位于同一个集合中的元素意味着它们被赋了相等的值,它们两两之间"=="
成立。建立完并查集,再次遍历equations
来检查方程组是否成立,如果遍历到的字符串包含"!="
,则检查字符串中包含的两个字符是否位于同一个集合中,如果位于一个集合,或者"!="
两边的两字符相等,则和之前构建的并查集矛盾,返回false
。如果遍历完所有包含!=
的字符串都没有返回false
,则证明方程组中的所有等式合法,返回true
建立并查集的方法是:
- 使用哈希表和存储所有集合,哈希表的键值设定为
int
类型,作为一个集合的root
节点;哈希表的每个键值对应一个集合Set
,存储这个集合中包含的所有字符(方程组中所有相互满足"=="
的字符) - 建立数组存储每个字符所在集合的
root
节点的值,初始化为0
代表还没有被存入一个集合 - 并查集中集合的新建、存入新字符、合并两个集合、查询一个字符所在的集合等基本操作这里不再介绍,详见下面的题解代码
题解代码:
class Solution {
//并查集问题
public boolean equationsPossible(String[] equations) {
HashMap<Integer,HashSet<Character>> unionSet=new HashMap<>(); //并查集
int[] rootMap=new int[26];
int rootValue=1;
for(int i=0;i<equations.length;i++)
{
String s=equations[i];
if(s.charAt(1)=='=')
{
char ch1=s.charAt(0),ch2=s.charAt(3);
if(rootMap[ch1-'a']==0)
{
if(rootMap[ch2-'a']==0)
{
//建立一个新并查集
rootMap[ch1-'a']=rootValue;
rootMap[ch2-'a']=rootValue;
HashSet<Character> tempSet=new HashSet<>();
tempSet.add(ch1);
tempSet.add(ch2);
unionSet.put(rootValue,tempSet);
rootValue+=1;
}
else
{
//ch1加入ch2所在的并查集中
rootMap[ch1-'a']=rootMap[ch2-'a'];
unionSet.get(rootMap[ch2-'a']).add(ch1);
}
}
else
{
if(rootMap[ch2-'a']==0)
{
//ch2加入ch1所在的并查集中
rootMap[ch2-'a']=rootMap[ch1-'a'];
unionSet.get(rootMap[ch1-'a']).add(ch2);
}
else if(ch1!=ch2 && rootMap[ch1-'a']!=rootMap[ch2-'a'])
{
//合并两个并查集
int index1=rootMap[ch1-'a'],index2=rootMap[ch2-'a'];
if(unionSet.get(index1).size()>=unionSet.get(index2).size())
{
mergeUnion(unionSet,rootMap,index1,index2);
}
else
{
mergeUnion(unionSet,rootMap,index2,index1);
}
}
}
}
}
//并查集建立完毕,接下来验证方程组的正确性
for(int i=0;i<equations.length;i++)
{
String s=equations[i];
if(s.charAt(1)=='!')
{
char ch1=s.charAt(0),ch2=s.charAt(3);
if(ch1==ch2)
{
return false;
}
else if(rootMap[ch1-'a']==rootMap[ch2-'a'] && rootMap[ch1-'a']!=0)
{
return false;
}
}
}
return true;
}
//将一个并查集合并到另一个并查集中
void mergeUnion(HashMap<Integer,HashSet<Character>> unionSet,int[] rootMap,int unionIndex1,int unionIndex2)
{
HashSet<Character> mergedSet=unionSet.get(unionIndex2); //将要被合并入其他并查集的并查集
for(char ch:mergedSet) //更改根节点
{
rootMap[ch-'a']=unionIndex1;
}
unionSet.get(unionIndex1).addAll(unionSet.get(unionIndex2)); //合并
unionSet.remove(unionIndex2); //删除被合并的并查集
}
}