题目链接:990. 等式方程的可满足性
分析:
题目意思很简单,给你一个字符串数组,根据字符串数组判断其中式子是否可以通过定义变量(既代值)成立。
我看到这个题,当时便分析出这是一道图的连通性的题目,可以使用并查集做。
并查集算法意思很简单,思维很巧妙,设置一个桶数组当做集合,此时每个集合中只有自己本身一个元素(既数组值指向数组下标值)。然后通过给的图的联通条件,不断的将集合归并的算法。我们将每个集合抽象为一个元素,该元素代表着一个集合,而该集合中的其他元素全部指向该元素,从而完成集合的划分。
根据上述分析我们可以很容易得出,我们需要一个输入某个元素返回某个集合的代表元素的方法,而该方法有递归和循环两种方式。
findroot函数代码
//递归
if (ch[c] != c) {
ch[c]=findroot(ch[c]);
return ch[c];
}
return c;
//循环
while(ch[c]!=c){
ch[c]=ch[ch[c]];
c=ch[c];
}
return c;
此处使用了一个技巧:路径压缩。相信大家很容易发现,当数据过多时,可能某个元素到集合代表元素的中间需要经过多次递归或循环。
而路径压缩就直接将该元素调整指向至集合代表元素,从来大大降低时间复杂度。
而归并的过程更为简单,我们直接将一个集合的代表元素指向另外一个集合的代表元素,如此两个集合便合并为一个集合。
merge函数代码
public void merge(int a, int b) {
int roota = findroot(a);
int rootb = findroot(b);
ch[roota] = rootb;
}
回到题目,我们先循环字符串数组在==时便将集合归并;在进行一轮循环,当字符串数组!=时,那么我们便判断两元素是否不为同一集合元素,若是,那么返回false;若不是,则继续循环。若第二次循环过程中没有返回false,那么返回true。
完整Java代码
class Solution {
int[] ch = new int[26];
public boolean equationsPossible(String[] equations) {
int len = equations.length;
for (int i = 0; i < 26; i++)
ch[i] = i;
for (String s : equations) {
if (s.charAt(1) == '=') {
merge(s.charAt(0) - 'a', s.charAt(3) - 'a');
}
}
for (String s : equations) {
if (s.charAt(1) == '!') {
if (findroot(s.charAt(0) - 'a') == findroot(s.charAt(3) - 'a')) {
return false;
}
}
}
return true;
}
public int findroot(int c) {
if (ch[c] != c) {
findroot(ch[c]);
}
return c;
}
public void merge(int a, int b) {
int roota = findroot(a);
int rootb = findroot(b);
ch[roota] = rootb;
}
}