题目描述
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a==b” 或 “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
例如:
输入:[“a==b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
思路
这道题可以用并查集解决,当多个字母相互之间有相等关系,那么可以认为他们是在同一个集合下的,因此在一个集合下的两个元素,我们可以认为是相等的,否则就是不等的。
那么我们可以创建一个字符集,遍历这个字符串数组,将他们所有相等的拿出来(字符串的下标1对应的元素为‘=’),然后将第一个元素(字符串的下标0)和第二个元素(字符串的下标3)在并查集中相关。
然后在遍历一次字符串数组,将其中所有不相等的拿出来(字符串的下标1对应的元素为‘!’),然后判断第一个元素(字符串的下标0)和第二个元素(字符串的下标3)是否属于同一个集合,如果属于说明是对的,否则直接返回false
需要注意的是,由于我们存储的是所有小写字母之间的关系,所以并查集的大小为26即可,而我们的数组是从0下标开始的。所以我们要想节省空间,应该将每个字母存储在字母的ascii 减 字符‘a’的ascii,否则会越界
有关并查集的知识可以看我的博客:Java——并查集
具体代码
class Solution {
public boolean equationsPossible(String[] equations) {
MyUnionFindSet ufs = new MyUnionFindSet(26);
for(int i = 0; i < equations.length; i++){
if(equations[i].charAt(1) == '='){
ufs.union(equations[i].charAt(0) - 'a',equations[i].charAt(3) - 'a');
}
}
for(int i = 0; i < equations.length; i++){
if(equations[i].charAt(1) == '!'){
if(ufs.isSameUnionFindSet(equations[i].charAt(0) - 'a'
,equations[i].charAt(3) - 'a')){
return false;
}
}
}
return true;
}
}
class MyUnionFindSet {
public int[] elem;
public int usedSize;
public MyUnionFindSet(int n){
this.elem = new int[n];
Arrays.fill(elem, -1);//初始化数组全为-1
}
/**
* 查询x1和x2是否在同一个集合中
* @param x1
* @param x2
* @return
*/
public boolean isSameUnionFindSet(int x1, int x2){
int index1 = findRoot(x1);
int index2 = findRoot(x2);
if(index1 == index2){
return true;
}
return false;
}
/**
* 查找x下标数据的根节点
* @param x
* @return 根节点的下标
*/
public int findRoot(int x){
if(x < 0){
throw new ArrayIndexOutOfBoundsException("下标不能是负数");
}
while(elem[x] >= 0){
x = elem[x];
}
return x;
}
/**
* 合并x1,x2所在的两个集合
* @param x1
* @param x2
*/
public void union(int x1, int x2){
int index1 = findRoot(x1);
int index2 = findRoot(x2);
if(index1 == index2){
System.out.println("x1和x2已经在同一个集合中了");
return;
}
elem[index1] = elem[index1] + elem[index2];
elem[index2] = index1;
}
public int getCount(){
int count = 0;
for (int x:elem) {
if(x < 0){
count++;
}
}
return count;
}
public void print(){
for (int x:elem) {
System.out.print(x + " ");
}
System.out.println();
}
}