给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:"a==b" 或 "a!=b"。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
示例 1:
输入: ["a==b","b!=a"]
输出: false
解释: 如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
示例 2:
输入: ["b==a","a==b"]
输出: true
解释: 我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。
示例 3:
输入: ["a==b","b==c","a==c"]
输出: true
示例 4:
输入: ["a==b","b!=c","c==a"]
输出: false
示例 5:
输入: ["c==c","b==d","x!=z"]
输出: true
提示:
1 <= equations.length <= 500equations[i].length == 4equations[i][0]和equations[i][3]是小写字母equations[i][1]要么是'=',要么是'!'equations[i][2]是'='
解题思路
- 首先处理所有等式,将相等关系的变量放在一个集合中,如果两个变量已经分别属于一个集合,则要将两个集合合并。
- 然后处理所有不等式,如果当前两个变量处于同一个集合,则无法同时满足相等与不等,返回
false。 - 如果所有方程处理完成没有无法满足的方程,则返回
true。
代码实现
// 等式的可传递性:小写z为ASCII=97
var equationsPossible = function(equations) {
let size = equations.length;
let uf = new UnionFind(26);
// 第一次扫描
for(str of equations){
if(str.charAt(1) == "="){
uf.unite(str.charCodeAt(0) - 97,str.charCodeAt(3)-97)
}
}
// 第二次扫描 判断!非等
for(str of equations){
if(str.charAt(1) == "!"){
if(uf.connected(str.charCodeAt(0) - 97 , str.charCodeAt(3)-97)){
return false;
}
}
}
return true;
};
// 并查集的模板
class UnionFind{
constructor(n){//初始化:并查集里面的所有节点的父节点都是自己
this.parent = new Array(n).fill(0).map((value,index)=>index);
this.size = new Array(n).fill(1); //初始化集合
this.setCount = n;//联通分量
}
findSet(index){
if(this.parent[index] != index){
this.parent[index] = this.findSet(this.parent[index]);
}
return this.parent[index];
}
unite(index1,index2){ //合并
// 拿到他们的丁点坐标
let root1 = this.findSet(index1), root2 = this.findSet(index2)
if(root1 != root2){
// 判断一下各自集合的节点个数,节点少的集合要往节点多的集合上面合并
if(root1 < root2){
[root1,root2] = [root2,root1]
}
// 合并根节点
this.parent[root2] = root1;
// 计算已经合并的节点数量
this.size[root1] += this.size[root2];
this.setCount --;//合并多少,城市数量则减一
}
}
getCount(){
return this.setCount;
}
connected(index1,index2){// 判断两个顶点,是否是一个连通分量
let root1 = this.findSet(index1),root2 = this.findSet(index2);
return root1 == root2;
}
}
至此我们就完成了leetcode-990-等式方程的可满足性