[路飞]_leetcode-990-等式方程的可满足性

134 阅读1分钟

[题目地址]

给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:"a==b" 或 "a!=b"。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。

只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。 

示例 1:

输入: ["a==b","b!=a"]
输出: false
解释: 如果我们指定,a = 1b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。

示例 2:

输入: ["b==a","a==b"]
输出: true
解释: 我们可以指定 a = 1b = 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. 1 <= equations.length <= 500
  2. equations[i].length == 4
  3. equations[i][0] 和 equations[i][3] 是小写字母
  4. equations[i][1] 要么是 '=',要么是 '!'
  5. equations[i][2] 是 '='

解题思路

  1. 首先处理所有等式,将相等关系的变量放在一个集合中,如果两个变量已经分别属于一个集合,则要将两个集合合并。
  2. 然后处理所有不等式,如果当前两个变量处于同一个集合,则无法同时满足相等与不等,返回 false
  3. 如果所有方程处理完成没有无法满足的方程,则返回 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-等式方程的可满足性